import { n as __exportAll, r as __toESM, t as __commonJSMin } from "./chunk-B-1-B7_t.js"; import { t as require_react } from "./react.js"; import { t as require_client } from "./react-dom_client.js"; import { $ as Camera, $i as OrthographicCamera$1, $n as InstancedMesh, As as UniformsUtils, Bo as Sphere$1, Br as LinearMipmapNearestFilter, Bs as Vector2, C as AnimationMixer, Da as RGBAFormat, Dn as Frustum, Dr as Line$1, Ea as RGBADepthPacking, Eo as SRGBColorSpace$2, Fa as RGBA_ASTC_4x4_Format, Fo as ShortType, Fr as LinearFilter, Fs as UnsignedIntType, Ft as CurvePath, Gi as OctahedronGeometry, Gn as ImageBitmapLoader, Go as SpotLight$1, Gr as LoaderUtils, Gs as VideoTexture$1, Hi as Object3D, Ho as Spherical, Hs as Vector4, Ht as DataTexture, Io as Skeleton, J as BufferAttribute, Jt as DepthFormat, K as BoxGeometry, Ka as RGBA_PVRTC_4BPPV1_Format, Kr as LoadingManager, Lo as SkeletonHelper, Lr as LinearMipMapLinearFilter, N as AudioListener, No as ShapePath, Nr as LineLoop, Oa as RGBAIntegerFormat, Oo as Scene, Or as Line3, Os as Uniform, Ot as CubicBezierCurve3, P as AudioLoader, Po as ShapeUtils, Pr as LineSegments, Pt as Curve, Qn as InstancedInterleavedBuffer, Qs as WireframeGeometry, Qt as DirectionalLight, Rn as GridHelper, Ro as SkinnedMesh, Rs as UnsignedShortType, Rt as CylinderGeometry, Sn as FloatType, Ti as NearestMipmapNearestFilter, Tt as CubeTextureLoader, U as Box2, Ua as RGBA_BPTC_Format, Us as VectorKeyframeTrack, Ut as DataTextureLoader, V as Bone, Vi as NumberKeyframeTrack, Vn as HalfFloatType, Vo as SphereGeometry, Vr as LinearSRGBColorSpace$2, Vs as Vector3, W as Box3, Wa as RGBA_ETC2_EAC_Format, Wn as IcosahedronGeometry, Wr as Loader$1, Wt as DataUtils, Xn as InstancedBufferAttribute, Xr as MOUSE, Xt as DepthTexture, Y as BufferGeometry, Ya as RGBA_S3TC_DXT5_Format, Ys as WebGLRenderTarget, Z as ByteType, Zn as InstancedBufferGeometry, Zr as Material, _a as QuadraticBezierCurve3, _i as MirroredRepeatWrapping, a as WebGLCubeRenderTarget, aa as PlaneGeometry, ai as Mesh, ao as RGB_S3TC_DXT1_Format, ar as InterleavedBufferAttribute, bt as CubeCamera$1, ci as MeshDistanceMaterial, cn as EdgesGeometry, co as RGIntegerFormat, cr as InterpolateDiscrete, cs as TOUCH, ct as Color, di as MeshNormalMaterial, do as Raycaster, ds as Texture$1, ei as MathUtils, et as CameraHelper, fi as MeshPhongMaterial, fs as TextureLoader, gn as EventDispatcher$2, gs as TorusGeometry, hn as Euler, i as UniformsLib, ia as Plane$1, io as RGB_PVRTC_4BPPV1_Format, ir as InterleavedBuffer, jo as Shape$1, js as UnsignedByteType, ko as ShaderMaterial, kr as LineBasicMaterial, la as Points$1, li as MeshLambertMaterial, ln as EllipseCurve, lr as InterpolateLinear, ma as PropertyBinding, mi as MeshStandardMaterial, mo as RedIntegerFormat, mr as KeepStencilOp, mt as CompressedTexture, n as ShaderChunk, na as Path, ni as Matrix3, no as RGB_ETC2_Format, o as WebGLRenderer, oi as MeshBasicMaterial, on as DynamicDrawUsage, or as Interpolant, ot as ClampToEdgeWrapping, pi as MeshPhysicalMaterial, po as RedFormat, qt as DefaultLoadingManager, ra as PerspectiveCamera$1, ri as Matrix4, rr as IntType, rt as CatmullRomCurve3, sa as PointLight, si as MeshDepthMaterial, so as RGFormat, st as Clock, to as RGB_ETC1_Format, tt as CanvasTexture, ua as PointsMaterial, uo as Ray, va as Quaternion, vn as ExtrudeGeometry, vo as RepeatWrapping, vs as Triangle, wi as NearestMipmapLinearFilter, ws as Uint16BufferAttribute, x as AnimationClip, xi as NearestFilter, xn as Float32BufferAttribute, y as AmbientLight, ya as QuaternionKeyframeTrack, yn as FileLoader, yo as ReplaceStencilOp, z as BatchedMesh, za as RGBA_ASTC_6x6_Format, zn as Group, zr as LinearMipmapLinearFilter } from "./three.module-DxhMWCDR.js"; import { A as clear$1, D as useLoader, E as useInstanceHandle, M as suspend, N as require_with_selector, a as addEffect, c as applyProps, g as extend, i as addAfterEffect, j as preload, k as useThree, p as createPortal, u as context$10, w as useFrame } from "./react-three-fiber.esm-CIxUR0B5.js"; import { create as create$2 } from "./zustand.js"; //#region node_modules/@babel/runtime/helpers/esm/extends.js function _extends$1() { return _extends$1 = Object.assign ? Object.assign.bind() : function(n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$1.apply(null, arguments); } //#endregion //#region node_modules/@react-three/drei/web/Html.js var import_react = /* @__PURE__ */ __toESM(require_react()); var import_client = /* @__PURE__ */ __toESM(require_client()); var v1 = /* @__PURE__ */ new Vector3(); var v2 = /* @__PURE__ */ new Vector3(); var v3 = /* @__PURE__ */ new Vector3(); var v4 = /* @__PURE__ */ new Vector2(); function defaultCalculatePosition(el, camera, size) { const objectPos = v1.setFromMatrixPosition(el.matrixWorld); objectPos.project(camera); const widthHalf = size.width / 2; const heightHalf = size.height / 2; return [objectPos.x * widthHalf + widthHalf, -(objectPos.y * heightHalf) + heightHalf]; } function isObjectBehindCamera(el, camera) { const objectPos = v1.setFromMatrixPosition(el.matrixWorld); const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld); const deltaCamObj = objectPos.sub(cameraPos); const camDir = camera.getWorldDirection(v3); return deltaCamObj.angleTo(camDir) > Math.PI / 2; } function isObjectVisible(el, camera, raycaster, occlude) { const elPos = v1.setFromMatrixPosition(el.matrixWorld); const screenPos = elPos.clone(); screenPos.project(camera); v4.set(screenPos.x, screenPos.y); raycaster.setFromCamera(v4, camera); const intersects = raycaster.intersectObjects(occlude, true); if (intersects.length) { const intersectionDistance = intersects[0].distance; return elPos.distanceTo(raycaster.ray.origin) < intersectionDistance; } return true; } function objectScale(el, camera) { if (camera instanceof OrthographicCamera$1) return camera.zoom; else if (camera instanceof PerspectiveCamera$1) { const objectPos = v1.setFromMatrixPosition(el.matrixWorld); const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld); const vFOV = camera.fov * Math.PI / 180; const dist = objectPos.distanceTo(cameraPos); return 1 / (2 * Math.tan(vFOV / 2) * dist); } else return 1; } function objectZIndex(el, camera, zIndexRange) { if (camera instanceof PerspectiveCamera$1 || camera instanceof OrthographicCamera$1) { const objectPos = v1.setFromMatrixPosition(el.matrixWorld); const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld); const dist = objectPos.distanceTo(cameraPos); const A = (zIndexRange[1] - zIndexRange[0]) / (camera.far - camera.near); const B = zIndexRange[1] - A * camera.far; return Math.round(A * dist + B); } } var epsilon = (value) => Math.abs(value) < 1e-10 ? 0 : value; function getCSSMatrix(matrix, multipliers, prepend = "") { let matrix3d = "matrix3d("; for (let i = 0; i !== 16; i++) matrix3d += epsilon(multipliers[i] * matrix.elements[i]) + (i !== 15 ? "," : ")"); return prepend + matrix3d; } var getCameraCSSMatrix = ((multipliers) => { return (matrix) => getCSSMatrix(matrix, multipliers); })([ 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1 ]); var getObjectCSSMatrix = ((scaleMultipliers) => { return (matrix, factor) => getCSSMatrix(matrix, scaleMultipliers(factor), "translate(-50%,-50%)"); })((f) => [ 1 / f, 1 / f, 1 / f, 1, -1 / f, -1 / f, -1 / f, -1, 1 / f, 1 / f, 1 / f, 1, 1, 1, 1, 1 ]); function isRefObject$1(ref) { return ref && typeof ref === "object" && "current" in ref; } var Html = /* @__PURE__ */ import_react.forwardRef(({ children, eps = .001, style, className, prepend, center, fullscreen, portal, distanceFactor, sprite = false, transform = false, occlude, onOcclude, castShadow, receiveShadow, material, geometry, zIndexRange = [16777271, 0], calculatePosition = defaultCalculatePosition, as = "div", wrapperClass, pointerEvents = "auto", ...props }, ref) => { const { gl, camera, scene, size, raycaster, events, viewport } = useThree(); const [el] = import_react.useState(() => document.createElement(as)); const root = import_react.useRef(null); const group = import_react.useRef(null); const oldZoom = import_react.useRef(0); const oldPosition = import_react.useRef([0, 0]); const transformOuterRef = import_react.useRef(null); const transformInnerRef = import_react.useRef(null); const target = (portal == null ? void 0 : portal.current) || events.connected || gl.domElement.parentNode; const occlusionMeshRef = import_react.useRef(null); const isMeshSizeSet = import_react.useRef(false); const isRayCastOcclusion = import_react.useMemo(() => { return occlude && occlude !== "blending" || Array.isArray(occlude) && occlude.length && isRefObject$1(occlude[0]); }, [occlude]); import_react.useLayoutEffect(() => { const el = gl.domElement; if (occlude && occlude === "blending") { el.style.zIndex = `${Math.floor(zIndexRange[0] / 2)}`; el.style.position = "absolute"; el.style.pointerEvents = "none"; } else { el.style.zIndex = null; el.style.position = null; el.style.pointerEvents = null; } }, [occlude]); import_react.useLayoutEffect(() => { if (group.current) { const currentRoot = root.current = import_client.createRoot(el); scene.updateMatrixWorld(); if (transform) el.style.cssText = `position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;`; else { const vec = calculatePosition(group.current, camera, size); el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(${vec[0]}px,${vec[1]}px,0);transform-origin:0 0;`; } if (target) if (prepend) target.prepend(el); else target.appendChild(el); return () => { if (target) target.removeChild(el); currentRoot.unmount(); }; } }, [target, transform]); import_react.useLayoutEffect(() => { if (wrapperClass) el.className = wrapperClass; }, [wrapperClass]); const styles = import_react.useMemo(() => { if (transform) return { position: "absolute", top: 0, left: 0, width: size.width, height: size.height, transformStyle: "preserve-3d", pointerEvents: "none" }; else return { position: "absolute", transform: center ? "translate3d(-50%,-50%,0)" : "none", ...fullscreen && { top: -size.height / 2, left: -size.width / 2, width: size.width, height: size.height }, ...style }; }, [ style, center, fullscreen, size, transform ]); const transformInnerStyles = import_react.useMemo(() => ({ position: "absolute", pointerEvents }), [pointerEvents]); import_react.useLayoutEffect(() => { isMeshSizeSet.current = false; if (transform) { var _root$current; (_root$current = root.current) == null || _root$current.render(/*#__PURE__*/ import_react.createElement("div", { ref: transformOuterRef, style: styles }, /*#__PURE__*/ import_react.createElement("div", { ref: transformInnerRef, style: transformInnerStyles }, /*#__PURE__*/ import_react.createElement("div", { ref, className, style, children })))); } else { var _root$current2; (_root$current2 = root.current) == null || _root$current2.render(/*#__PURE__*/ import_react.createElement("div", { ref, style: styles, className, children })); } }); const visible = import_react.useRef(true); useFrame((gl) => { if (group.current) { camera.updateMatrixWorld(); group.current.updateWorldMatrix(true, false); const vec = transform ? oldPosition.current : calculatePosition(group.current, camera, size); if (transform || Math.abs(oldZoom.current - camera.zoom) > eps || Math.abs(oldPosition.current[0] - vec[0]) > eps || Math.abs(oldPosition.current[1] - vec[1]) > eps) { const isBehindCamera = isObjectBehindCamera(group.current, camera); let raytraceTarget = false; if (isRayCastOcclusion) { if (Array.isArray(occlude)) raytraceTarget = occlude.map((item) => item.current); else if (occlude !== "blending") raytraceTarget = [scene]; } const previouslyVisible = visible.current; if (raytraceTarget) visible.current = isObjectVisible(group.current, camera, raycaster, raytraceTarget) && !isBehindCamera; else visible.current = !isBehindCamera; if (previouslyVisible !== visible.current) if (onOcclude) onOcclude(!visible.current); else el.style.display = visible.current ? "block" : "none"; const halfRange = Math.floor(zIndexRange[0] / 2); const zRange = occlude ? isRayCastOcclusion ? [zIndexRange[0], halfRange] : [halfRange - 1, 0] : zIndexRange; el.style.zIndex = `${objectZIndex(group.current, camera, zRange)}`; if (transform) { const [widthHalf, heightHalf] = [size.width / 2, size.height / 2]; const fov = camera.projectionMatrix.elements[5] * heightHalf; const { isOrthographicCamera, top, left, bottom, right } = camera; const cameraMatrix = getCameraCSSMatrix(camera.matrixWorldInverse); const cameraTransform = isOrthographicCamera ? `scale(${fov})translate(${epsilon(-(right + left) / 2)}px,${epsilon((top + bottom) / 2)}px)` : `translateZ(${fov}px)`; let matrix = group.current.matrixWorld; if (sprite) { matrix = camera.matrixWorldInverse.clone().transpose().copyPosition(matrix).scale(group.current.scale); matrix.elements[3] = matrix.elements[7] = matrix.elements[11] = 0; matrix.elements[15] = 1; } el.style.width = size.width + "px"; el.style.height = size.height + "px"; el.style.perspective = isOrthographicCamera ? "" : `${fov}px`; if (transformOuterRef.current && transformInnerRef.current) { transformOuterRef.current.style.transform = `${cameraTransform}${cameraMatrix}translate(${widthHalf}px,${heightHalf}px)`; transformInnerRef.current.style.transform = getObjectCSSMatrix(matrix, 1 / ((distanceFactor || 10) / 400)); } } else { const scale = distanceFactor === void 0 ? 1 : objectScale(group.current, camera) * distanceFactor; el.style.transform = `translate3d(${vec[0]}px,${vec[1]}px,0) scale(${scale})`; } oldPosition.current = vec; oldZoom.current = camera.zoom; } } if (!isRayCastOcclusion && occlusionMeshRef.current && !isMeshSizeSet.current) if (transform) { if (transformOuterRef.current) { const el = transformOuterRef.current.children[0]; if (el != null && el.clientWidth && el != null && el.clientHeight) { const { isOrthographicCamera } = camera; if (isOrthographicCamera || geometry) { if (props.scale) if (!Array.isArray(props.scale)) occlusionMeshRef.current.scale.setScalar(1 / props.scale); else if (props.scale instanceof Vector3) occlusionMeshRef.current.scale.copy(props.scale.clone().divideScalar(1)); else occlusionMeshRef.current.scale.set(1 / props.scale[0], 1 / props.scale[1], 1 / props.scale[2]); } else { const ratio = (distanceFactor || 10) / 400; const w = el.clientWidth * ratio; const h = el.clientHeight * ratio; occlusionMeshRef.current.scale.set(w, h, 1); } isMeshSizeSet.current = true; } } } else { const ele = el.children[0]; if (ele != null && ele.clientWidth && ele != null && ele.clientHeight) { const ratio = 1 / viewport.factor; const w = ele.clientWidth * ratio; const h = ele.clientHeight * ratio; occlusionMeshRef.current.scale.set(w, h, 1); isMeshSizeSet.current = true; } occlusionMeshRef.current.lookAt(gl.camera.position); } }); const shaders = import_react.useMemo(() => ({ vertexShader: !transform ? ` /* This shader is from the THREE's SpriteMaterial. We need to turn the backing plane into a Sprite (make it always face the camera) if "transfrom" is false. */ #include void main() { vec2 center = vec2(0., 1.); float rotation = 0.0; // This is somewhat arbitrary, but it seems to work well // Need to figure out how to derive this dynamically if it even matters float size = 0.03; vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 ); vec2 scale; scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) ); scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) ); bool isPerspective = isPerspectiveMatrix( projectionMatrix ); if ( isPerspective ) scale *= - mvPosition.z; vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale * size; vec2 rotatedPosition; rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; mvPosition.xy += rotatedPosition; gl_Position = projectionMatrix * mvPosition; } ` : void 0, fragmentShader: ` void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); } ` }), [transform]); return /*#__PURE__*/ import_react.createElement("group", _extends$1({}, props, { ref: group }), occlude && !isRayCastOcclusion && /*#__PURE__*/ import_react.createElement("mesh", { castShadow, receiveShadow, ref: occlusionMeshRef }, geometry || /*#__PURE__*/ import_react.createElement("planeGeometry", null), material || /*#__PURE__*/ import_react.createElement("shaderMaterial", { side: 2, vertexShader: shaders.vertexShader, fragmentShader: shaders.fragmentShader }))); }); //#endregion //#region node_modules/@react-three/drei/web/CycleRaycast.js function CycleRaycast({ onChanged, portal, preventDefault = true, scroll = true, keyCode = 9 }) { const cycle = import_react.useRef(0); const setEvents = useThree((state) => state.setEvents); const get = useThree((state) => state.get); const gl = useThree((state) => state.gl); import_react.useEffect(() => { var _portal$current; let hits = []; let lastEvent = void 0; const prev = get().events.filter; const target = (_portal$current = portal == null ? void 0 : portal.current) !== null && _portal$current !== void 0 ? _portal$current : gl.domElement.parentNode; const renderStatus = () => target && onChanged && onChanged(hits, Math.round(cycle.current) % hits.length); setEvents({ filter: (intersections, state) => { let clone = [...intersections]; if (clone.length !== hits.length || !hits.every((hit) => clone.map((e) => e.object.uuid).includes(hit.object.uuid))) { cycle.current = 0; hits = clone; renderStatus(); } if (prev) clone = prev(clone, state); for (let i = 0; i < Math.round(cycle.current) % clone.length; i++) { const first = clone.shift(); clone = [...clone, first]; } return clone; } }); const refresh = (fn) => { var _get$events$handlers, _get$events$handlers2; cycle.current = fn(cycle.current); (_get$events$handlers = get().events.handlers) == null || _get$events$handlers.onPointerCancel(void 0); (_get$events$handlers2 = get().events.handlers) == null || _get$events$handlers2.onPointerMove(lastEvent); renderStatus(); }; const tabEvent = (event) => { if ((event.keyCode || event.which) === keyCode) { if (preventDefault) event.preventDefault(); if (hits.length > 1) refresh((current) => current + 1); } }; const wheelEvent = (event) => { if (preventDefault) event.preventDefault(); let delta = 0; if (!event) event = window.event; if (event.wheelDelta) delta = event.wheelDelta / 120; else if (event.detail) delta = -event.detail / 3; if (hits.length > 1) refresh((current) => Math.abs(current - delta)); }; const moveEvent = (event) => lastEvent = event; document.addEventListener("pointermove", moveEvent, { passive: true }); if (scroll) document.addEventListener("wheel", wheelEvent); if (keyCode !== void 0) document.addEventListener("keydown", tabEvent); return () => { setEvents({ filter: prev }); if (keyCode !== void 0) document.removeEventListener("keydown", tabEvent); if (scroll) document.removeEventListener("wheel", wheelEvent); document.removeEventListener("pointermove", moveEvent); }; }, [ gl, get, setEvents, preventDefault, scroll, keyCode ]); return null; } //#endregion //#region node_modules/@react-three/drei/web/useCursor.js function useCursor(hovered, onPointerOver = "pointer", onPointerOut = "auto", container = document.body) { import_react.useEffect(() => { if (hovered) { container.style.cursor = onPointerOver; return () => void (container.style.cursor = onPointerOut); } }, [hovered]); } //#endregion //#region node_modules/@react-three/drei/core/Progress.js var saveLastTotalLoaded = 0; var useProgress = /* @__PURE__ */ create$2((set) => { DefaultLoadingManager.onStart = (item, loaded, total) => { set({ active: true, item, loaded, total, progress: (loaded - saveLastTotalLoaded) / (total - saveLastTotalLoaded) * 100 }); }; DefaultLoadingManager.onLoad = () => { set({ active: false }); }; DefaultLoadingManager.onError = (item) => set((state) => ({ errors: [...state.errors, item] })); DefaultLoadingManager.onProgress = (item, loaded, total) => { if (loaded === total) saveLastTotalLoaded = total; set({ active: true, item, loaded, total, progress: (loaded - saveLastTotalLoaded) / (total - saveLastTotalLoaded) * 100 || 100 }); }; return { errors: [], active: false, progress: 0, item: "", loaded: 0, total: 0 }; }); function Progress({ children }) { const result = useProgress(); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(result)); } //#endregion //#region node_modules/@react-three/drei/web/Loader.js var defaultDataInterpolation = (p) => `Loading ${p.toFixed(2)}%`; function Loader({ containerStyles, innerStyles, barStyles, dataStyles, dataInterpolation = defaultDataInterpolation, initialState = (active) => active }) { const { active, progress } = useProgress(); const progressRef = import_react.useRef(0); const rafRef = import_react.useRef(0); const progressSpanRef = import_react.useRef(null); const [shown, setShown] = import_react.useState(initialState(active)); import_react.useEffect(() => { let t; if (active !== shown) t = setTimeout(() => setShown(active), 300); return () => clearTimeout(t); }, [shown, active]); const updateProgress = import_react.useCallback(() => { if (!progressSpanRef.current) return; progressRef.current += (progress - progressRef.current) / 2; if (progressRef.current > .95 * progress || progress === 100) progressRef.current = progress; progressSpanRef.current.innerText = dataInterpolation(progressRef.current); if (progressRef.current < progress) rafRef.current = requestAnimationFrame(updateProgress); }, [dataInterpolation, progress]); import_react.useEffect(() => { updateProgress(); return () => cancelAnimationFrame(rafRef.current); }, [updateProgress]); return shown ? /*#__PURE__*/ import_react.createElement("div", { style: { ...styles.container, opacity: active ? 1 : 0, ...containerStyles } }, /*#__PURE__*/ import_react.createElement("div", null, /*#__PURE__*/ import_react.createElement("div", { style: { ...styles.inner, ...innerStyles } }, /*#__PURE__*/ import_react.createElement("div", { style: { ...styles.bar, transform: `scaleX(${progress / 100})`, ...barStyles } }), /*#__PURE__*/ import_react.createElement("span", { ref: progressSpanRef, style: { ...styles.data, ...dataStyles } })))) : null; } var styles = { container: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", background: "#171717", display: "flex", alignItems: "center", justifyContent: "center", transition: "opacity 300ms ease", zIndex: 1e3 }, inner: { width: 100, height: 3, background: "#272727", textAlign: "center" }, bar: { height: 3, width: "100%", background: "white", transition: "transform 200ms", transformOrigin: "left center" }, data: { display: "inline-block", position: "relative", fontVariantNumeric: "tabular-nums", marginTop: "0.8em", color: "#f0f0f0", fontSize: "0.6em", fontFamily: `-apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", "Helvetica Neue", Helvetica, Arial, Roboto, Ubuntu, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`, whiteSpace: "nowrap" } }; //#endregion //#region node_modules/@use-gesture/core/dist/maths-0ab39ae9.esm.js function clamp$2(v, min, max) { return Math.max(min, Math.min(v, max)); } var V = { toVector(v, fallback) { if (v === void 0) v = fallback; return Array.isArray(v) ? v : [v, v]; }, add(v1, v2) { return [v1[0] + v2[0], v1[1] + v2[1]]; }, sub(v1, v2) { return [v1[0] - v2[0], v1[1] - v2[1]]; }, addTo(v1, v2) { v1[0] += v2[0]; v1[1] += v2[1]; }, subTo(v1, v2) { v1[0] -= v2[0]; v1[1] -= v2[1]; } }; function rubberband(distance, dimension, constant) { if (dimension === 0 || Math.abs(dimension) === Infinity) return Math.pow(distance, constant * 5); return distance * dimension * constant / (dimension + constant * distance); } function rubberbandIfOutOfBounds(position, min, max, constant = .15) { if (constant === 0) return clamp$2(position, min, max); if (position < min) return -rubberband(min - position, max - min, constant) + min; if (position > max) return +rubberband(position - max, max - min, constant) + max; return position; } function computeRubberband(bounds, [Vx, Vy], [Rx, Ry]) { const [[X0, X1], [Y0, Y1]] = bounds; return [rubberbandIfOutOfBounds(Vx, X0, X1, Rx), rubberbandIfOutOfBounds(Vy, Y0, Y1, Ry)]; } //#endregion //#region node_modules/@use-gesture/core/dist/actions-fe213e88.esm.js function _toPrimitive$1(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== void 0) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey$1(arg) { var key = _toPrimitive$1(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _defineProperty$2(obj, key, value) { key = _toPropertyKey$1(key); if (key in obj) Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function(r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), !0).forEach(function(r) { _defineProperty$2(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function(r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var EVENT_TYPE_MAP = { pointer: { start: "down", change: "move", end: "up" }, mouse: { start: "down", change: "move", end: "up" }, touch: { start: "start", change: "move", end: "end" }, gesture: { start: "start", change: "change", end: "end" } }; function capitalize(string) { if (!string) return ""; return string[0].toUpperCase() + string.slice(1); } var actionsWithoutCaptureSupported = ["enter", "leave"]; function hasCapture(capture = false, actionKey) { return capture && !actionsWithoutCaptureSupported.includes(actionKey); } function toHandlerProp(device, action = "", capture = false) { const deviceProps = EVENT_TYPE_MAP[device]; const actionKey = deviceProps ? deviceProps[action] || action : action; return "on" + capitalize(device) + capitalize(actionKey) + (hasCapture(capture, actionKey) ? "Capture" : ""); } var pointerCaptureEvents = ["gotpointercapture", "lostpointercapture"]; function parseProp(prop) { let eventKey = prop.substring(2).toLowerCase(); const passive = !!~eventKey.indexOf("passive"); if (passive) eventKey = eventKey.replace("passive", ""); const captureKey = pointerCaptureEvents.includes(eventKey) ? "capturecapture" : "capture"; const capture = !!~eventKey.indexOf(captureKey); if (capture) eventKey = eventKey.replace("capture", ""); return { device: eventKey, capture, passive }; } function toDomEventType(device, action = "") { const deviceProps = EVENT_TYPE_MAP[device]; return device + (deviceProps ? deviceProps[action] || action : action); } function isTouch(event) { return "touches" in event; } function getPointerType(event) { if (isTouch(event)) return "touch"; if ("pointerType" in event) return event.pointerType; return "mouse"; } function getCurrentTargetTouchList(event) { return Array.from(event.touches).filter((e) => { var _event$currentTarget, _event$currentTarget$; return e.target === event.currentTarget || ((_event$currentTarget = event.currentTarget) === null || _event$currentTarget === void 0 || (_event$currentTarget$ = _event$currentTarget.contains) === null || _event$currentTarget$ === void 0 ? void 0 : _event$currentTarget$.call(_event$currentTarget, e.target)); }); } function getTouchList(event) { return event.type === "touchend" || event.type === "touchcancel" ? event.changedTouches : event.targetTouches; } function getValueEvent(event) { return isTouch(event) ? getTouchList(event)[0] : event; } function distanceAngle(P1, P2) { try { const dx = P2.clientX - P1.clientX; const dy = P2.clientY - P1.clientY; const cx = (P2.clientX + P1.clientX) / 2; const cy = (P2.clientY + P1.clientY) / 2; const distance = Math.hypot(dx, dy); return { angle: -(Math.atan2(dx, dy) * 180) / Math.PI, distance, origin: [cx, cy] }; } catch (_unused) {} return null; } function touchIds(event) { return getCurrentTargetTouchList(event).map((touch) => touch.identifier); } function touchDistanceAngle(event, ids) { const [P1, P2] = Array.from(event.touches).filter((touch) => ids.includes(touch.identifier)); return distanceAngle(P1, P2); } function pointerId(event) { const valueEvent = getValueEvent(event); return isTouch(event) ? valueEvent.identifier : valueEvent.pointerId; } function pointerValues(event) { const valueEvent = getValueEvent(event); return [valueEvent.clientX, valueEvent.clientY]; } var LINE_HEIGHT = 40; var PAGE_HEIGHT = 800; function wheelValues(event) { let { deltaX, deltaY, deltaMode } = event; if (deltaMode === 1) { deltaX *= LINE_HEIGHT; deltaY *= LINE_HEIGHT; } else if (deltaMode === 2) { deltaX *= PAGE_HEIGHT; deltaY *= PAGE_HEIGHT; } return [deltaX, deltaY]; } function scrollValues(event) { var _ref, _ref2; const { scrollX, scrollY, scrollLeft, scrollTop } = event.currentTarget; return [(_ref = scrollX !== null && scrollX !== void 0 ? scrollX : scrollLeft) !== null && _ref !== void 0 ? _ref : 0, (_ref2 = scrollY !== null && scrollY !== void 0 ? scrollY : scrollTop) !== null && _ref2 !== void 0 ? _ref2 : 0]; } function getEventDetails(event) { const payload = {}; if ("buttons" in event) payload.buttons = event.buttons; if ("shiftKey" in event) { const { shiftKey, altKey, metaKey, ctrlKey } = event; Object.assign(payload, { shiftKey, altKey, metaKey, ctrlKey }); } return payload; } function call$1(v, ...args) { if (typeof v === "function") return v(...args); else return v; } function noop$1() {} function chain(...fns) { if (fns.length === 0) return noop$1; if (fns.length === 1) return fns[0]; return function() { let result; for (const fn of fns) result = fn.apply(this, arguments) || result; return result; }; } function assignDefault(value, fallback) { return Object.assign({}, fallback, value || {}); } var BEFORE_LAST_KINEMATICS_DELAY = 32; var Engine = class { constructor(ctrl, args, key) { this.ctrl = ctrl; this.args = args; this.key = key; if (!this.state) { this.state = {}; this.computeValues([0, 0]); this.computeInitial(); if (this.init) this.init(); this.reset(); } } get state() { return this.ctrl.state[this.key]; } set state(state) { this.ctrl.state[this.key] = state; } get shared() { return this.ctrl.state.shared; } get eventStore() { return this.ctrl.gestureEventStores[this.key]; } get timeoutStore() { return this.ctrl.gestureTimeoutStores[this.key]; } get config() { return this.ctrl.config[this.key]; } get sharedConfig() { return this.ctrl.config.shared; } get handler() { return this.ctrl.handlers[this.key]; } reset() { const { state, shared, ingKey, args } = this; shared[ingKey] = state._active = state.active = state._blocked = state._force = false; state._step = [false, false]; state.intentional = false; state._movement = [0, 0]; state._distance = [0, 0]; state._direction = [0, 0]; state._delta = [0, 0]; state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]; state.args = args; state.axis = void 0; state.memo = void 0; state.elapsedTime = state.timeDelta = 0; state.direction = [0, 0]; state.distance = [0, 0]; state.overflow = [0, 0]; state._movementBound = [false, false]; state.velocity = [0, 0]; state.movement = [0, 0]; state.delta = [0, 0]; state.timeStamp = 0; } start(event) { const state = this.state; const config = this.config; if (!state._active) { this.reset(); this.computeInitial(); state._active = true; state.target = event.target; state.currentTarget = event.currentTarget; state.lastOffset = config.from ? call$1(config.from, state) : state.offset; state.offset = state.lastOffset; state.startTime = state.timeStamp = event.timeStamp; } } computeValues(values) { const state = this.state; state._values = values; state.values = this.config.transform(values); } computeInitial() { const state = this.state; state._initial = state._values; state.initial = state.values; } compute(event) { const { state, config, shared } = this; state.args = this.args; let dt = 0; if (event) { state.event = event; if (config.preventDefault && event.cancelable) state.event.preventDefault(); state.type = event.type; shared.touches = this.ctrl.pointerIds.size || this.ctrl.touchIds.size; shared.locked = !!document.pointerLockElement; Object.assign(shared, getEventDetails(event)); shared.down = shared.pressed = shared.buttons % 2 === 1 || shared.touches > 0; dt = event.timeStamp - state.timeStamp; state.timeStamp = event.timeStamp; state.elapsedTime = state.timeStamp - state.startTime; } if (state._active) { const _absoluteDelta = state._delta.map(Math.abs); V.addTo(state._distance, _absoluteDelta); } if (this.axisIntent) this.axisIntent(event); const [_m0, _m1] = state._movement; const [t0, t1] = config.threshold; const { _step, values } = state; if (config.hasCustomTransform) { if (_step[0] === false) _step[0] = Math.abs(_m0) >= t0 && values[0]; if (_step[1] === false) _step[1] = Math.abs(_m1) >= t1 && values[1]; } else { if (_step[0] === false) _step[0] = Math.abs(_m0) >= t0 && Math.sign(_m0) * t0; if (_step[1] === false) _step[1] = Math.abs(_m1) >= t1 && Math.sign(_m1) * t1; } state.intentional = _step[0] !== false || _step[1] !== false; if (!state.intentional) return; const movement = [0, 0]; if (config.hasCustomTransform) { const [v0, v1] = values; movement[0] = _step[0] !== false ? v0 - _step[0] : 0; movement[1] = _step[1] !== false ? v1 - _step[1] : 0; } else { movement[0] = _step[0] !== false ? _m0 - _step[0] : 0; movement[1] = _step[1] !== false ? _m1 - _step[1] : 0; } if (this.restrictToAxis && !state._blocked) this.restrictToAxis(movement); const previousOffset = state.offset; const gestureIsActive = state._active && !state._blocked || state.active; if (gestureIsActive) { state.first = state._active && !state.active; state.last = !state._active && state.active; state.active = shared[this.ingKey] = state._active; if (event) { if (state.first) { if ("bounds" in config) state._bounds = call$1(config.bounds, state); if (this.setup) this.setup(); } state.movement = movement; this.computeOffset(); } } const [ox, oy] = state.offset; const [[x0, x1], [y0, y1]] = state._bounds; state.overflow = [ox < x0 ? -1 : ox > x1 ? 1 : 0, oy < y0 ? -1 : oy > y1 ? 1 : 0]; state._movementBound[0] = state.overflow[0] ? state._movementBound[0] === false ? state._movement[0] : state._movementBound[0] : false; state._movementBound[1] = state.overflow[1] ? state._movementBound[1] === false ? state._movement[1] : state._movementBound[1] : false; const rubberband = state._active ? config.rubberband || [0, 0] : [0, 0]; state.offset = computeRubberband(state._bounds, state.offset, rubberband); state.delta = V.sub(state.offset, previousOffset); this.computeMovement(); if (gestureIsActive && (!state.last || dt > BEFORE_LAST_KINEMATICS_DELAY)) { state.delta = V.sub(state.offset, previousOffset); const absoluteDelta = state.delta.map(Math.abs); V.addTo(state.distance, absoluteDelta); state.direction = state.delta.map(Math.sign); state._direction = state._delta.map(Math.sign); if (!state.first && dt > 0) { state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]; state.timeDelta = dt; } } } emit() { const state = this.state; const shared = this.shared; const config = this.config; if (!state._active) this.clean(); if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return; const memo = this.handler(_objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, shared), state), {}, { [this.aliasKey]: state.values })); if (memo !== void 0) state.memo = memo; } clean() { this.eventStore.clean(); this.timeoutStore.clean(); } }; function selectAxis([dx, dy], threshold) { const absDx = Math.abs(dx); const absDy = Math.abs(dy); if (absDx > absDy && absDx > threshold) return "x"; if (absDy > absDx && absDy > threshold) return "y"; } var CoordinatesEngine = class extends Engine { constructor(...args) { super(...args); _defineProperty$2(this, "aliasKey", "xy"); } reset() { super.reset(); this.state.axis = void 0; } init() { this.state.offset = [0, 0]; this.state.lastOffset = [0, 0]; } computeOffset() { this.state.offset = V.add(this.state.lastOffset, this.state.movement); } computeMovement() { this.state.movement = V.sub(this.state.offset, this.state.lastOffset); } axisIntent(event) { const state = this.state; const config = this.config; if (!state.axis && event) { const threshold = typeof config.axisThreshold === "object" ? config.axisThreshold[getPointerType(event)] : config.axisThreshold; state.axis = selectAxis(state._movement, threshold); } state._blocked = (config.lockDirection || !!config.axis) && !state.axis || !!config.axis && config.axis !== state.axis; } restrictToAxis(v) { if (this.config.axis || this.config.lockDirection) switch (this.state.axis) { case "x": v[1] = 0; break; case "y": v[0] = 0; break; } } }; var identity$1 = (v) => v; var DEFAULT_RUBBERBAND = .15; var commonConfigResolver = { enabled(value = true) { return value; }, eventOptions(value, _k, config) { return _objectSpread2$1(_objectSpread2$1({}, config.shared.eventOptions), value); }, preventDefault(value = false) { return value; }, triggerAllEvents(value = false) { return value; }, rubberband(value = 0) { switch (value) { case true: return [DEFAULT_RUBBERBAND, DEFAULT_RUBBERBAND]; case false: return [0, 0]; default: return V.toVector(value); } }, from(value) { if (typeof value === "function") return value; if (value != null) return V.toVector(value); }, transform(value, _k, config) { const transform = value || config.shared.transform; this.hasCustomTransform = !!transform; { const originalTransform = transform || identity$1; return (v) => { const r = originalTransform(v); if (!isFinite(r[0]) || !isFinite(r[1])) console.warn(`[@use-gesture]: config.transform() must produce a valid result, but it was: [${r[0]},1]`); return r; }; } return transform || identity$1; }, threshold(value) { return V.toVector(value, 0); } }; Object.assign(commonConfigResolver, { domTarget(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`); return NaN; }, lockDirection(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`lockDirection\` option has been merged with \`axis\`. Use it as in \`{ axis: 'lock' }\``); return NaN; }, initial(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`initial\` option has been renamed to \`from\`.`); return NaN; } }); var DEFAULT_AXIS_THRESHOLD = 0; var coordinatesConfigResolver = _objectSpread2$1(_objectSpread2$1({}, commonConfigResolver), {}, { axis(_v, _k, { axis }) { this.lockDirection = axis === "lock"; if (!this.lockDirection) return axis; }, axisThreshold(value = DEFAULT_AXIS_THRESHOLD) { return value; }, bounds(value = {}) { if (typeof value === "function") return (state) => coordinatesConfigResolver.bounds(value(state)); if ("current" in value) return () => value.current; if (typeof HTMLElement === "function" && value instanceof HTMLElement) return value; const { left = -Infinity, right = Infinity, top = -Infinity, bottom = Infinity } = value; return [[left, right], [top, bottom]]; } }); var KEYS_DELTA_MAP = { ArrowRight: (displacement, factor = 1) => [displacement * factor, 0], ArrowLeft: (displacement, factor = 1) => [-1 * displacement * factor, 0], ArrowUp: (displacement, factor = 1) => [0, -1 * displacement * factor], ArrowDown: (displacement, factor = 1) => [0, displacement * factor] }; var DragEngine = class extends CoordinatesEngine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "dragging"); } reset() { super.reset(); const state = this.state; state._pointerId = void 0; state._pointerActive = false; state._keyboardActive = false; state._preventScroll = false; state._delayed = false; state.swipe = [0, 0]; state.tap = false; state.canceled = false; state.cancel = this.cancel.bind(this); } setup() { const state = this.state; if (state._bounds instanceof HTMLElement) { const boundRect = state._bounds.getBoundingClientRect(); const targetRect = state.currentTarget.getBoundingClientRect(); const _bounds = { left: boundRect.left - targetRect.left + state.offset[0], right: boundRect.right - targetRect.right + state.offset[0], top: boundRect.top - targetRect.top + state.offset[1], bottom: boundRect.bottom - targetRect.bottom + state.offset[1] }; state._bounds = coordinatesConfigResolver.bounds(_bounds); } } cancel() { const state = this.state; if (state.canceled) return; state.canceled = true; state._active = false; setTimeout(() => { this.compute(); this.emit(); }, 0); } setActive() { this.state._active = this.state._pointerActive || this.state._keyboardActive; } clean() { this.pointerClean(); this.state._pointerActive = false; this.state._keyboardActive = false; super.clean(); } pointerDown(event) { const config = this.config; const state = this.state; if (event.buttons != null && (Array.isArray(config.pointerButtons) ? !config.pointerButtons.includes(event.buttons) : config.pointerButtons !== -1 && config.pointerButtons !== event.buttons)) return; const ctrlIds = this.ctrl.setEventIds(event); if (config.pointerCapture) event.target.setPointerCapture(event.pointerId); if (ctrlIds && ctrlIds.size > 1 && state._pointerActive) return; this.start(event); this.setupPointer(event); state._pointerId = pointerId(event); state._pointerActive = true; this.computeValues(pointerValues(event)); this.computeInitial(); if (config.preventScrollAxis && getPointerType(event) !== "mouse") { state._active = false; this.setupScrollPrevention(event); } else if (config.delay > 0) { this.setupDelayTrigger(event); if (config.triggerAllEvents) { this.compute(event); this.emit(); } } else this.startPointerDrag(event); } startPointerDrag(event) { const state = this.state; state._active = true; state._preventScroll = true; state._delayed = false; this.compute(event); this.emit(); } pointerMove(event) { const state = this.state; const config = this.config; if (!state._pointerActive) return; const id = pointerId(event); if (state._pointerId !== void 0 && id !== state._pointerId) return; const _values = pointerValues(event); if (document.pointerLockElement === event.target) state._delta = [event.movementX, event.movementY]; else { state._delta = V.sub(_values, state._values); this.computeValues(_values); } V.addTo(state._movement, state._delta); this.compute(event); if (state._delayed && state.intentional) { this.timeoutStore.remove("dragDelay"); state.active = false; this.startPointerDrag(event); return; } if (config.preventScrollAxis && !state._preventScroll) if (state.axis) if (state.axis === config.preventScrollAxis || config.preventScrollAxis === "xy") { state._active = false; this.clean(); return; } else { this.timeoutStore.remove("startPointerDrag"); this.startPointerDrag(event); return; } else return; this.emit(); } pointerUp(event) { this.ctrl.setEventIds(event); try { if (this.config.pointerCapture && event.target.hasPointerCapture(event.pointerId)) event.target.releasePointerCapture(event.pointerId); } catch (_unused) { console.warn(`[@use-gesture]: If you see this message, it's likely that you're using an outdated version of \`@react-three/fiber\`. \n\nPlease upgrade to the latest version.`); } const state = this.state; const config = this.config; if (!state._active || !state._pointerActive) return; const id = pointerId(event); if (state._pointerId !== void 0 && id !== state._pointerId) return; this.state._pointerActive = false; this.setActive(); this.compute(event); const [dx, dy] = state._distance; state.tap = dx <= config.tapsThreshold && dy <= config.tapsThreshold; if (state.tap && config.filterTaps) state._force = true; else { const [_dx, _dy] = state._delta; const [_mx, _my] = state._movement; const [svx, svy] = config.swipe.velocity; const [sx, sy] = config.swipe.distance; const sdt = config.swipe.duration; if (state.elapsedTime < sdt) { const _vx = Math.abs(_dx / state.timeDelta); const _vy = Math.abs(_dy / state.timeDelta); if (_vx > svx && Math.abs(_mx) > sx) state.swipe[0] = Math.sign(_dx); if (_vy > svy && Math.abs(_my) > sy) state.swipe[1] = Math.sign(_dy); } } this.emit(); } pointerClick(event) { if (!this.state.tap && event.detail > 0) { event.preventDefault(); event.stopPropagation(); } } setupPointer(event) { const config = this.config; const device = config.device; try { if (device === "pointer" && config.preventScrollDelay === void 0) { const currentTarget = "uv" in event ? event.sourceEvent.currentTarget : event.currentTarget; if (window.getComputedStyle(currentTarget).touchAction === "auto") console.warn(`[@use-gesture]: The drag target has its \`touch-action\` style property set to \`auto\`. It is recommended to add \`touch-action: 'none'\` so that the drag gesture behaves correctly on touch-enabled devices. For more information read this: https://use-gesture.netlify.app/docs/extras/#touch-action.\n\nThis message will only show in development mode. It won't appear in production. If this is intended, you can ignore it.`, currentTarget); } } catch (_unused2) {} if (config.pointerLock) event.currentTarget.requestPointerLock(); if (!config.pointerCapture) { this.eventStore.add(this.sharedConfig.window, device, "change", this.pointerMove.bind(this)); this.eventStore.add(this.sharedConfig.window, device, "end", this.pointerUp.bind(this)); this.eventStore.add(this.sharedConfig.window, device, "cancel", this.pointerUp.bind(this)); } } pointerClean() { if (this.config.pointerLock && document.pointerLockElement === this.state.currentTarget) document.exitPointerLock(); } preventScroll(event) { if (this.state._preventScroll && event.cancelable) event.preventDefault(); } setupScrollPrevention(event) { this.state._preventScroll = false; persistEvent(event); const remove = this.eventStore.add(this.sharedConfig.window, "touch", "change", this.preventScroll.bind(this), { passive: false }); this.eventStore.add(this.sharedConfig.window, "touch", "end", remove); this.eventStore.add(this.sharedConfig.window, "touch", "cancel", remove); this.timeoutStore.add("startPointerDrag", this.startPointerDrag.bind(this), this.config.preventScrollDelay, event); } setupDelayTrigger(event) { this.state._delayed = true; this.timeoutStore.add("dragDelay", () => { this.state._step = [0, 0]; this.startPointerDrag(event); }, this.config.delay); } keyDown(event) { const deltaFn = KEYS_DELTA_MAP[event.key]; if (deltaFn) { const state = this.state; const factor = event.shiftKey ? 10 : event.altKey ? .1 : 1; this.start(event); state._delta = deltaFn(this.config.keyboardDisplacement, factor); state._keyboardActive = true; V.addTo(state._movement, state._delta); this.compute(event); this.emit(); } } keyUp(event) { if (!(event.key in KEYS_DELTA_MAP)) return; this.state._keyboardActive = false; this.setActive(); this.compute(event); this.emit(); } bind(bindFunction) { const device = this.config.device; bindFunction(device, "start", this.pointerDown.bind(this)); if (this.config.pointerCapture) { bindFunction(device, "change", this.pointerMove.bind(this)); bindFunction(device, "end", this.pointerUp.bind(this)); bindFunction(device, "cancel", this.pointerUp.bind(this)); bindFunction("lostPointerCapture", "", this.pointerUp.bind(this)); } if (this.config.keys) { bindFunction("key", "down", this.keyDown.bind(this)); bindFunction("key", "up", this.keyUp.bind(this)); } if (this.config.filterTaps) bindFunction("click", "", this.pointerClick.bind(this), { capture: true, passive: false }); } }; function persistEvent(event) { "persist" in event && typeof event.persist === "function" && event.persist(); } var isBrowser = typeof window !== "undefined" && window.document && window.document.createElement; function supportsTouchEvents() { return isBrowser && "ontouchstart" in window; } function isTouchScreen() { return supportsTouchEvents() || isBrowser && window.navigator.maxTouchPoints > 1; } function supportsPointerEvents() { return isBrowser && "onpointerdown" in window; } function supportsPointerLock() { return isBrowser && "exitPointerLock" in window.document; } function supportsGestureEvents() { try { return "constructor" in GestureEvent; } catch (e) { return false; } } var SUPPORT = { isBrowser, gesture: supportsGestureEvents(), touch: supportsTouchEvents(), touchscreen: isTouchScreen(), pointer: supportsPointerEvents(), pointerLock: supportsPointerLock() }; var DEFAULT_PREVENT_SCROLL_DELAY = 250; var DEFAULT_DRAG_DELAY = 180; var DEFAULT_SWIPE_VELOCITY = .5; var DEFAULT_SWIPE_DISTANCE = 50; var DEFAULT_SWIPE_DURATION = 250; var DEFAULT_KEYBOARD_DISPLACEMENT = 10; var DEFAULT_DRAG_AXIS_THRESHOLD = { mouse: 0, touch: 0, pen: 8 }; var dragConfigResolver = _objectSpread2$1(_objectSpread2$1({}, coordinatesConfigResolver), {}, { device(_v, _k, { pointer: { touch = false, lock = false, mouse = false } = {} }) { this.pointerLock = lock && SUPPORT.pointerLock; if (SUPPORT.touch && touch) return "touch"; if (this.pointerLock) return "mouse"; if (SUPPORT.pointer && !mouse) return "pointer"; if (SUPPORT.touch) return "touch"; return "mouse"; }, preventScrollAxis(value, _k, { preventScroll }) { this.preventScrollDelay = typeof preventScroll === "number" ? preventScroll : preventScroll || preventScroll === void 0 && value ? DEFAULT_PREVENT_SCROLL_DELAY : void 0; if (!SUPPORT.touchscreen || preventScroll === false) return void 0; return value ? value : preventScroll !== void 0 ? "y" : void 0; }, pointerCapture(_v, _k, { pointer: { capture = true, buttons = 1, keys = true } = {} }) { this.pointerButtons = buttons; this.keys = keys; return !this.pointerLock && this.device === "pointer" && capture; }, threshold(value, _k, { filterTaps = false, tapsThreshold = 3, axis = void 0 }) { const threshold = V.toVector(value, filterTaps ? tapsThreshold : axis ? 1 : 0); this.filterTaps = filterTaps; this.tapsThreshold = tapsThreshold; return threshold; }, swipe({ velocity = DEFAULT_SWIPE_VELOCITY, distance = DEFAULT_SWIPE_DISTANCE, duration = DEFAULT_SWIPE_DURATION } = {}) { return { velocity: this.transform(V.toVector(velocity)), distance: this.transform(V.toVector(distance)), duration }; }, delay(value = 0) { switch (value) { case true: return DEFAULT_DRAG_DELAY; case false: return 0; default: return value; } }, axisThreshold(value) { if (!value) return DEFAULT_DRAG_AXIS_THRESHOLD; return _objectSpread2$1(_objectSpread2$1({}, DEFAULT_DRAG_AXIS_THRESHOLD), value); }, keyboardDisplacement(value = DEFAULT_KEYBOARD_DISPLACEMENT) { return value; } }); Object.assign(dragConfigResolver, { useTouch(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`useTouch\` option has been renamed to \`pointer.touch\`. Use it as in \`{ pointer: { touch: true } }\`.`); return NaN; }, experimental_preventWindowScrollY(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`experimental_preventWindowScrollY\` option has been renamed to \`preventScroll\`.`); return NaN; }, swipeVelocity(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`swipeVelocity\` option has been renamed to \`swipe.velocity\`. Use it as in \`{ swipe: { velocity: 0.5 } }\`.`); return NaN; }, swipeDistance(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`swipeDistance\` option has been renamed to \`swipe.distance\`. Use it as in \`{ swipe: { distance: 50 } }\`.`); return NaN; }, swipeDuration(value) { if (value !== void 0) throw Error(`[@use-gesture]: \`swipeDuration\` option has been renamed to \`swipe.duration\`. Use it as in \`{ swipe: { duration: 250 } }\`.`); return NaN; } }); function clampStateInternalMovementToBounds(state) { const [ox, oy] = state.overflow; const [dx, dy] = state._delta; const [dirx, diry] = state._direction; if (ox < 0 && dx > 0 && dirx < 0 || ox > 0 && dx < 0 && dirx > 0) state._movement[0] = state._movementBound[0]; if (oy < 0 && dy > 0 && diry < 0 || oy > 0 && dy < 0 && diry > 0) state._movement[1] = state._movementBound[1]; } var SCALE_ANGLE_RATIO_INTENT_DEG = 30; var PINCH_WHEEL_RATIO = 100; var PinchEngine = class extends Engine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "pinching"); _defineProperty$2(this, "aliasKey", "da"); } init() { this.state.offset = [1, 0]; this.state.lastOffset = [1, 0]; this.state._pointerEvents = /* @__PURE__ */ new Map(); } reset() { super.reset(); const state = this.state; state._touchIds = []; state.canceled = false; state.cancel = this.cancel.bind(this); state.turns = 0; } computeOffset() { const { type, movement, lastOffset } = this.state; if (type === "wheel") this.state.offset = V.add(movement, lastOffset); else this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]]; } computeMovement() { const { offset, lastOffset } = this.state; this.state.movement = [offset[0] / lastOffset[0], offset[1] - lastOffset[1]]; } axisIntent() { const state = this.state; const [_m0, _m1] = state._movement; if (!state.axis) { const axisMovementDifference = Math.abs(_m0) * SCALE_ANGLE_RATIO_INTENT_DEG - Math.abs(_m1); if (axisMovementDifference < 0) state.axis = "angle"; else if (axisMovementDifference > 0) state.axis = "scale"; } } restrictToAxis(v) { if (this.config.lockDirection) { if (this.state.axis === "scale") v[1] = 0; else if (this.state.axis === "angle") v[0] = 0; } } cancel() { const state = this.state; if (state.canceled) return; setTimeout(() => { state.canceled = true; state._active = false; this.compute(); this.emit(); }, 0); } touchStart(event) { this.ctrl.setEventIds(event); const state = this.state; const ctrlTouchIds = this.ctrl.touchIds; if (state._active) { if (state._touchIds.every((id) => ctrlTouchIds.has(id))) return; } if (ctrlTouchIds.size < 2) return; this.start(event); state._touchIds = Array.from(ctrlTouchIds).slice(0, 2); const payload = touchDistanceAngle(event, state._touchIds); if (!payload) return; this.pinchStart(event, payload); } pointerStart(event) { if (event.buttons != null && event.buttons % 2 !== 1) return; this.ctrl.setEventIds(event); event.target.setPointerCapture(event.pointerId); const state = this.state; const _pointerEvents = state._pointerEvents; const ctrlPointerIds = this.ctrl.pointerIds; if (state._active) { if (Array.from(_pointerEvents.keys()).every((id) => ctrlPointerIds.has(id))) return; } if (_pointerEvents.size < 2) _pointerEvents.set(event.pointerId, event); if (state._pointerEvents.size < 2) return; this.start(event); const payload = distanceAngle(...Array.from(_pointerEvents.values())); if (!payload) return; this.pinchStart(event, payload); } pinchStart(event, payload) { const state = this.state; state.origin = payload.origin; this.computeValues([payload.distance, payload.angle]); this.computeInitial(); this.compute(event); this.emit(); } touchMove(event) { if (!this.state._active) return; const payload = touchDistanceAngle(event, this.state._touchIds); if (!payload) return; this.pinchMove(event, payload); } pointerMove(event) { const _pointerEvents = this.state._pointerEvents; if (_pointerEvents.has(event.pointerId)) _pointerEvents.set(event.pointerId, event); if (!this.state._active) return; const payload = distanceAngle(...Array.from(_pointerEvents.values())); if (!payload) return; this.pinchMove(event, payload); } pinchMove(event, payload) { const state = this.state; const prev_a = state._values[1]; const delta_a = payload.angle - prev_a; let delta_turns = 0; if (Math.abs(delta_a) > 270) delta_turns += Math.sign(delta_a); this.computeValues([payload.distance, payload.angle - 360 * delta_turns]); state.origin = payload.origin; state.turns = delta_turns; state._movement = [state._values[0] / state._initial[0] - 1, state._values[1] - state._initial[1]]; this.compute(event); this.emit(); } touchEnd(event) { this.ctrl.setEventIds(event); if (!this.state._active) return; if (this.state._touchIds.some((id) => !this.ctrl.touchIds.has(id))) { this.state._active = false; this.compute(event); this.emit(); } } pointerEnd(event) { const state = this.state; this.ctrl.setEventIds(event); try { event.target.releasePointerCapture(event.pointerId); } catch (_unused) {} if (state._pointerEvents.has(event.pointerId)) state._pointerEvents.delete(event.pointerId); if (!state._active) return; if (state._pointerEvents.size < 2) { state._active = false; this.compute(event); this.emit(); } } gestureStart(event) { if (event.cancelable) event.preventDefault(); const state = this.state; if (state._active) return; this.start(event); this.computeValues([event.scale, event.rotation]); state.origin = [event.clientX, event.clientY]; this.compute(event); this.emit(); } gestureMove(event) { if (event.cancelable) event.preventDefault(); if (!this.state._active) return; const state = this.state; this.computeValues([event.scale, event.rotation]); state.origin = [event.clientX, event.clientY]; const _previousMovement = state._movement; state._movement = [event.scale - 1, event.rotation]; state._delta = V.sub(state._movement, _previousMovement); this.compute(event); this.emit(); } gestureEnd(event) { if (!this.state._active) return; this.state._active = false; this.compute(event); this.emit(); } wheel(event) { const modifierKey = this.config.modifierKey; if (modifierKey && (Array.isArray(modifierKey) ? !modifierKey.find((k) => event[k]) : !event[modifierKey])) return; if (!this.state._active) this.wheelStart(event); else this.wheelChange(event); this.timeoutStore.add("wheelEnd", this.wheelEnd.bind(this)); } wheelStart(event) { this.start(event); this.wheelChange(event); } wheelChange(event) { if (!("uv" in event)) { if (event.cancelable) event.preventDefault(); if (!event.defaultPrevented) console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option.\n\nThis message will only appear in development mode.`); } const state = this.state; state._delta = [-wheelValues(event)[1] / PINCH_WHEEL_RATIO * state.offset[0], 0]; V.addTo(state._movement, state._delta); clampStateInternalMovementToBounds(state); this.state.origin = [event.clientX, event.clientY]; this.compute(event); this.emit(); } wheelEnd() { if (!this.state._active) return; this.state._active = false; this.compute(); this.emit(); } bind(bindFunction) { const device = this.config.device; if (!!device) { bindFunction(device, "start", this[device + "Start"].bind(this)); bindFunction(device, "change", this[device + "Move"].bind(this)); bindFunction(device, "end", this[device + "End"].bind(this)); bindFunction(device, "cancel", this[device + "End"].bind(this)); bindFunction("lostPointerCapture", "", this[device + "End"].bind(this)); } if (this.config.pinchOnWheel) bindFunction("wheel", "", this.wheel.bind(this), { passive: false }); } }; var pinchConfigResolver = _objectSpread2$1(_objectSpread2$1({}, commonConfigResolver), {}, { device(_v, _k, { shared, pointer: { touch = false } = {} }) { if (shared.target && !SUPPORT.touch && SUPPORT.gesture) return "gesture"; if (SUPPORT.touch && touch) return "touch"; if (SUPPORT.touchscreen) { if (SUPPORT.pointer) return "pointer"; if (SUPPORT.touch) return "touch"; } }, bounds(_v, _k, { scaleBounds = {}, angleBounds = {} }) { const _scaleBounds = (state) => { const D = assignDefault(call$1(scaleBounds, state), { min: -Infinity, max: Infinity }); return [D.min, D.max]; }; const _angleBounds = (state) => { const A = assignDefault(call$1(angleBounds, state), { min: -Infinity, max: Infinity }); return [A.min, A.max]; }; if (typeof scaleBounds !== "function" && typeof angleBounds !== "function") return [_scaleBounds(), _angleBounds()]; return (state) => [_scaleBounds(state), _angleBounds(state)]; }, threshold(value, _k, config) { this.lockDirection = config.axis === "lock"; return V.toVector(value, this.lockDirection ? [.1, 3] : 0); }, modifierKey(value) { if (value === void 0) return "ctrlKey"; return value; }, pinchOnWheel(value = true) { return value; } }); var MoveEngine = class extends CoordinatesEngine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "moving"); } move(event) { if (this.config.mouseOnly && event.pointerType !== "mouse") return; if (!this.state._active) this.moveStart(event); else this.moveChange(event); this.timeoutStore.add("moveEnd", this.moveEnd.bind(this)); } moveStart(event) { this.start(event); this.computeValues(pointerValues(event)); this.compute(event); this.computeInitial(); this.emit(); } moveChange(event) { if (!this.state._active) return; const values = pointerValues(event); const state = this.state; state._delta = V.sub(values, state._values); V.addTo(state._movement, state._delta); this.computeValues(values); this.compute(event); this.emit(); } moveEnd(event) { if (!this.state._active) return; this.state._active = false; this.compute(event); this.emit(); } bind(bindFunction) { bindFunction("pointer", "change", this.move.bind(this)); bindFunction("pointer", "leave", this.moveEnd.bind(this)); } }; var moveConfigResolver = _objectSpread2$1(_objectSpread2$1({}, coordinatesConfigResolver), {}, { mouseOnly: (value = true) => value }); var ScrollEngine = class extends CoordinatesEngine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "scrolling"); } scroll(event) { if (!this.state._active) this.start(event); this.scrollChange(event); this.timeoutStore.add("scrollEnd", this.scrollEnd.bind(this)); } scrollChange(event) { if (event.cancelable) event.preventDefault(); const state = this.state; const values = scrollValues(event); state._delta = V.sub(values, state._values); V.addTo(state._movement, state._delta); this.computeValues(values); this.compute(event); this.emit(); } scrollEnd() { if (!this.state._active) return; this.state._active = false; this.compute(); this.emit(); } bind(bindFunction) { bindFunction("scroll", "", this.scroll.bind(this)); } }; var scrollConfigResolver = coordinatesConfigResolver; var WheelEngine = class extends CoordinatesEngine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "wheeling"); } wheel(event) { if (!this.state._active) this.start(event); this.wheelChange(event); this.timeoutStore.add("wheelEnd", this.wheelEnd.bind(this)); } wheelChange(event) { const state = this.state; state._delta = wheelValues(event); V.addTo(state._movement, state._delta); clampStateInternalMovementToBounds(state); this.compute(event); this.emit(); } wheelEnd() { if (!this.state._active) return; this.state._active = false; this.compute(); this.emit(); } bind(bindFunction) { bindFunction("wheel", "", this.wheel.bind(this)); } }; var wheelConfigResolver = coordinatesConfigResolver; var HoverEngine = class extends CoordinatesEngine { constructor(...args) { super(...args); _defineProperty$2(this, "ingKey", "hovering"); } enter(event) { if (this.config.mouseOnly && event.pointerType !== "mouse") return; this.start(event); this.computeValues(pointerValues(event)); this.compute(event); this.emit(); } leave(event) { if (this.config.mouseOnly && event.pointerType !== "mouse") return; const state = this.state; if (!state._active) return; state._active = false; const values = pointerValues(event); state._movement = state._delta = V.sub(values, state._values); this.computeValues(values); this.compute(event); state.delta = state.movement; this.emit(); } bind(bindFunction) { bindFunction("pointer", "enter", this.enter.bind(this)); bindFunction("pointer", "leave", this.leave.bind(this)); } }; var hoverConfigResolver = _objectSpread2$1(_objectSpread2$1({}, coordinatesConfigResolver), {}, { mouseOnly: (value = true) => value }); var EngineMap = /* @__PURE__ */ new Map(); var ConfigResolverMap = /* @__PURE__ */ new Map(); function registerAction(action) { EngineMap.set(action.key, action.engine); ConfigResolverMap.set(action.key, action.resolver); } var dragAction = { key: "drag", engine: DragEngine, resolver: dragConfigResolver }; var hoverAction = { key: "hover", engine: HoverEngine, resolver: hoverConfigResolver }; var moveAction = { key: "move", engine: MoveEngine, resolver: moveConfigResolver }; var pinchAction = { key: "pinch", engine: PinchEngine, resolver: pinchConfigResolver }; var scrollAction = { key: "scroll", engine: ScrollEngine, resolver: scrollConfigResolver }; var wheelAction = { key: "wheel", engine: WheelEngine, resolver: wheelConfigResolver }; //#endregion //#region node_modules/@use-gesture/core/dist/use-gesture-core.esm.js function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } var sharedConfigResolver = { target(value) { if (value) return () => "current" in value ? value.current : value; }, enabled(value = true) { return value; }, window(value = SUPPORT.isBrowser ? window : void 0) { return value; }, eventOptions({ passive = true, capture = false } = {}) { return { passive, capture }; }, transform(value) { return value; } }; var _excluded = [ "target", "eventOptions", "window", "enabled", "transform" ]; function resolveWith(config = {}, resolvers) { const result = {}; for (const [key, resolver] of Object.entries(resolvers)) switch (typeof resolver) { case "function": { const r = resolver.call(result, config[key], key, config); if (!Number.isNaN(r)) result[key] = r; } break; case "object": result[key] = resolveWith(config[key], resolver); break; case "boolean": if (resolver) result[key] = config[key]; break; } return result; } function parse(newConfig, gestureKey, _config = {}) { const _ref = newConfig, { target, eventOptions, window, enabled, transform } = _ref, rest = _objectWithoutProperties(_ref, _excluded); _config.shared = resolveWith({ target, eventOptions, window, enabled, transform }, sharedConfigResolver); if (gestureKey) { const resolver = ConfigResolverMap.get(gestureKey); _config[gestureKey] = resolveWith(_objectSpread2$1({ shared: _config.shared }, rest), resolver); } else for (const key in rest) { const resolver = ConfigResolverMap.get(key); if (resolver) _config[key] = resolveWith(_objectSpread2$1({ shared: _config.shared }, rest[key]), resolver); else if (![ "drag", "pinch", "scroll", "wheel", "move", "hover" ].includes(key)) { if (key === "domTarget") throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`); console.warn(`[@use-gesture]: Unknown config key \`${key}\` was used. Please read the documentation for further information.`); } } return _config; } var EventStore = class { constructor(ctrl, gestureKey) { _defineProperty$2(this, "_listeners", /* @__PURE__ */ new Set()); this._ctrl = ctrl; this._gestureKey = gestureKey; } add(element, device, action, handler, options) { const listeners = this._listeners; const type = toDomEventType(device, action); const eventOptions = _objectSpread2$1(_objectSpread2$1({}, this._gestureKey ? this._ctrl.config[this._gestureKey].eventOptions : {}), options); element.addEventListener(type, handler, eventOptions); const remove = () => { element.removeEventListener(type, handler, eventOptions); listeners.delete(remove); }; listeners.add(remove); return remove; } clean() { this._listeners.forEach((remove) => remove()); this._listeners.clear(); } }; var TimeoutStore = class { constructor() { _defineProperty$2(this, "_timeouts", /* @__PURE__ */ new Map()); } add(key, callback, ms = 140, ...args) { this.remove(key); this._timeouts.set(key, window.setTimeout(callback, ms, ...args)); } remove(key) { const timeout = this._timeouts.get(key); if (timeout) window.clearTimeout(timeout); } clean() { this._timeouts.forEach((timeout) => void window.clearTimeout(timeout)); this._timeouts.clear(); } }; var Controller = class { constructor(handlers) { _defineProperty$2(this, "gestures", /* @__PURE__ */ new Set()); _defineProperty$2(this, "_targetEventStore", new EventStore(this)); _defineProperty$2(this, "gestureEventStores", {}); _defineProperty$2(this, "gestureTimeoutStores", {}); _defineProperty$2(this, "handlers", {}); _defineProperty$2(this, "config", {}); _defineProperty$2(this, "pointerIds", /* @__PURE__ */ new Set()); _defineProperty$2(this, "touchIds", /* @__PURE__ */ new Set()); _defineProperty$2(this, "state", { shared: { shiftKey: false, metaKey: false, ctrlKey: false, altKey: false } }); resolveGestures(this, handlers); } setEventIds(event) { if (isTouch(event)) { this.touchIds = new Set(touchIds(event)); return this.touchIds; } else if ("pointerId" in event) { if (event.type === "pointerup" || event.type === "pointercancel") this.pointerIds.delete(event.pointerId); else if (event.type === "pointerdown") this.pointerIds.add(event.pointerId); return this.pointerIds; } } applyHandlers(handlers, nativeHandlers) { this.handlers = handlers; this.nativeHandlers = nativeHandlers; } applyConfig(config, gestureKey) { this.config = parse(config, gestureKey, this.config); } clean() { this._targetEventStore.clean(); for (const key of this.gestures) { this.gestureEventStores[key].clean(); this.gestureTimeoutStores[key].clean(); } } effect() { if (this.config.shared.target) this.bind(); return () => this._targetEventStore.clean(); } bind(...args) { const sharedConfig = this.config.shared; const props = {}; let target; if (sharedConfig.target) { target = sharedConfig.target(); if (!target) return; } if (sharedConfig.enabled) { for (const gestureKey of this.gestures) { const gestureConfig = this.config[gestureKey]; const bindFunction = bindToProps(props, gestureConfig.eventOptions, !!target); if (gestureConfig.enabled) new (EngineMap.get(gestureKey))(this, args, gestureKey).bind(bindFunction); } const nativeBindFunction = bindToProps(props, sharedConfig.eventOptions, !!target); for (const eventKey in this.nativeHandlers) nativeBindFunction(eventKey, "", (event) => this.nativeHandlers[eventKey](_objectSpread2$1(_objectSpread2$1({}, this.state.shared), {}, { event, args })), void 0, true); } for (const handlerProp in props) props[handlerProp] = chain(...props[handlerProp]); if (!target) return props; for (const handlerProp in props) { const { device, capture, passive } = parseProp(handlerProp); this._targetEventStore.add(target, device, "", props[handlerProp], { capture, passive }); } } }; function setupGesture(ctrl, gestureKey) { ctrl.gestures.add(gestureKey); ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl, gestureKey); ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore(); } function resolveGestures(ctrl, internalHandlers) { if (internalHandlers.drag) setupGesture(ctrl, "drag"); if (internalHandlers.wheel) setupGesture(ctrl, "wheel"); if (internalHandlers.scroll) setupGesture(ctrl, "scroll"); if (internalHandlers.move) setupGesture(ctrl, "move"); if (internalHandlers.pinch) setupGesture(ctrl, "pinch"); if (internalHandlers.hover) setupGesture(ctrl, "hover"); } var bindToProps = (props, eventOptions, withPassiveOption) => (device, action, handler, options = {}, isNative = false) => { var _options$capture, _options$passive; const capture = (_options$capture = options.capture) !== null && _options$capture !== void 0 ? _options$capture : eventOptions.capture; const passive = (_options$passive = options.passive) !== null && _options$passive !== void 0 ? _options$passive : eventOptions.passive; let handlerProp = isNative ? device : toHandlerProp(device, action, capture); if (withPassiveOption && passive) handlerProp += "Passive"; props[handlerProp] = props[handlerProp] || []; props[handlerProp].push(handler); }; var RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; function sortHandlers(_handlers) { const native = {}; const handlers = {}; const actions = /* @__PURE__ */ new Set(); for (let key in _handlers) if (RE_NOT_NATIVE.test(key)) { actions.add(RegExp.lastMatch); handlers[key] = _handlers[key]; } else native[key] = _handlers[key]; return [ handlers, native, actions ]; } function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { if (!actions.has(handlerKey)) return; if (!EngineMap.has(key)) { console.warn(`[@use-gesture]: You've created a custom handler that that uses the \`${key}\` gesture but isn't properly configured.\n\nPlease add \`${key}Action\` when creating your handler.`); return; } const startKey = handlerKey + "Start"; const endKey = handlerKey + "End"; const fn = (state) => { let memo = void 0; if (state.first && startKey in handlers) handlers[startKey](state); if (handlerKey in handlers) memo = handlers[handlerKey](state); if (state.last && endKey in handlers) handlers[endKey](state); return memo; }; internalHandlers[key] = fn; config[key] = config[key] || {}; } function parseMergedHandlers(mergedHandlers, mergedConfig) { const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); const internalHandlers = {}; registerGesture(actions, handlers, "onDrag", "drag", internalHandlers, mergedConfig); registerGesture(actions, handlers, "onWheel", "wheel", internalHandlers, mergedConfig); registerGesture(actions, handlers, "onScroll", "scroll", internalHandlers, mergedConfig); registerGesture(actions, handlers, "onPinch", "pinch", internalHandlers, mergedConfig); registerGesture(actions, handlers, "onMove", "move", internalHandlers, mergedConfig); registerGesture(actions, handlers, "onHover", "hover", internalHandlers, mergedConfig); return { handlers: internalHandlers, config: mergedConfig, nativeHandlers }; } //#endregion //#region node_modules/@use-gesture/react/dist/use-gesture-react.esm.js function useRecognizers(handlers, config = {}, gestureKey, nativeHandlers) { const ctrl = import_react.useMemo(() => new Controller(handlers), []); ctrl.applyHandlers(handlers, nativeHandlers); ctrl.applyConfig(config, gestureKey); import_react.useEffect(ctrl.effect.bind(ctrl)); import_react.useEffect(() => { return ctrl.clean.bind(ctrl); }, []); if (config.target === void 0) return ctrl.bind.bind(ctrl); } function createUseGesture(actions) { actions.forEach(registerAction); return function useGesture(_handlers, _config) { const { handlers, nativeHandlers, config } = parseMergedHandlers(_handlers, _config || {}); return useRecognizers(handlers, config, void 0, nativeHandlers); }; } function useGesture(handlers, config) { return createUseGesture([ dragAction, pinchAction, scrollAction, wheelAction, moveAction, hoverAction ])(handlers, config || {}); } //#endregion //#region node_modules/@react-three/drei/web/DragControls.js var initialModelPosition = /* @__PURE__ */ new Vector3(); var mousePosition2D = /* @__PURE__ */ new Vector2(); var mousePosition3D = /* @__PURE__ */ new Vector3(); var dragOffset = /* @__PURE__ */ new Vector3(); var dragPlaneNormal = /* @__PURE__ */ new Vector3(); var dragPlane = /* @__PURE__ */ new Plane$1(); var DragControls = /*#__PURE__*/ import_react.forwardRef(({ autoTransform = true, matrix, axisLock, dragLimits, onHover, onDragStart, onDrag, onDragEnd, children, dragConfig, ...props }, fRef) => { const defaultControls = useThree((state) => state.controls); const { camera, size, raycaster, invalidate } = useThree(); const ref = import_react.useRef(null); const bind = useGesture({ onHover: ({ hovering }) => onHover && onHover(hovering !== null && hovering !== void 0 ? hovering : false), onDragStart: ({ event }) => { if (defaultControls) defaultControls.enabled = false; const { point } = event; ref.current.matrix.decompose(initialModelPosition, new Quaternion(), new Vector3()); mousePosition3D.copy(point); dragOffset.copy(mousePosition3D).sub(initialModelPosition); onDragStart && onDragStart(initialModelPosition); invalidate(); }, onDrag: ({ xy: [dragX, dragY], intentional }) => { if (!intentional) return; const normalizedMouseX = (dragX - size.left) / size.width * 2 - 1; const normalizedMouseY = -((dragY - size.top) / size.height) * 2 + 1; mousePosition2D.set(normalizedMouseX, normalizedMouseY); raycaster.setFromCamera(mousePosition2D, camera); if (!axisLock) camera.getWorldDirection(dragPlaneNormal).negate(); else switch (axisLock) { case "x": dragPlaneNormal.set(1, 0, 0); break; case "y": dragPlaneNormal.set(0, 1, 0); break; case "z": dragPlaneNormal.set(0, 0, 1); break; } dragPlane.setFromNormalAndCoplanarPoint(dragPlaneNormal, mousePosition3D); raycaster.ray.intersectPlane(dragPlane, mousePosition3D); const previousLocalMatrix = ref.current.matrix.clone(); const previousWorldMatrix = ref.current.matrixWorld.clone(); const intendedNewPosition = new Vector3(mousePosition3D.x - dragOffset.x, mousePosition3D.y - dragOffset.y, mousePosition3D.z - dragOffset.z); if (dragLimits) { intendedNewPosition.x = dragLimits[0] ? Math.max(Math.min(intendedNewPosition.x, dragLimits[0][1]), dragLimits[0][0]) : intendedNewPosition.x; intendedNewPosition.y = dragLimits[1] ? Math.max(Math.min(intendedNewPosition.y, dragLimits[1][1]), dragLimits[1][0]) : intendedNewPosition.y; intendedNewPosition.z = dragLimits[2] ? Math.max(Math.min(intendedNewPosition.z, dragLimits[2][1]), dragLimits[2][0]) : intendedNewPosition.z; } if (autoTransform) { ref.current.matrix.setPosition(intendedNewPosition); const deltaLocalMatrix = ref.current.matrix.clone().multiply(previousLocalMatrix.invert()); const deltaWorldMatrix = ref.current.matrix.clone().multiply(previousWorldMatrix.invert()); onDrag && onDrag(ref.current.matrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix); } else { const tempMatrix = new Matrix4().copy(ref.current.matrix); tempMatrix.setPosition(intendedNewPosition); const deltaLocalMatrix = tempMatrix.clone().multiply(previousLocalMatrix.invert()); const deltaWorldMatrix = tempMatrix.clone().multiply(previousWorldMatrix.invert()); onDrag && onDrag(tempMatrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix); } invalidate(); }, onDragEnd: () => { if (defaultControls) defaultControls.enabled = true; onDragEnd && onDragEnd(); invalidate(); } }, { drag: { filterTaps: true, threshold: 1, ...typeof dragConfig === "object" ? dragConfig : {} } }); import_react.useImperativeHandle(fRef, () => ref.current, []); import_react.useLayoutEffect(() => { if (!matrix) return; ref.current.matrix = matrix; }, [matrix]); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, bind(), { matrix, matrixAutoUpdate: false }, props), children); }); //#endregion //#region node_modules/maath/dist/objectSpread2-284232a6.esm.js function _defineProperty$1(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } //#endregion //#region node_modules/maath/dist/isNativeReflectConstruct-5594d075.esm.js function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {})); return true; } catch (e) { return false; } } //#endregion //#region node_modules/maath/dist/matrix-baa530bf.esm.js /** * * @param terms * * | a b c | * | d e f | * | g h i | * * @returns {number} determinant */ function determinant3() { for (var _len2 = arguments.length, terms = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) terms[_key2] = arguments[_key2]; var a = terms[0], b = terms[1], c = terms[2], d = terms[3], e = terms[4], f = terms[5], g = terms[6], h = terms[7], i = terms[8]; return a * e * i + b * f * g + c * d * h - c * e * g - b * d * i - a * f * h; } /** * */ function matrixSum3(m1, m2) { var sum = []; var m1Array = m1.toArray(); var m2Array = m2.toArray(); for (var i = 0; i < m1Array.length; i++) sum[i] = m1Array[i] + m2Array[i]; return new Matrix3().fromArray(sum); } //#endregion //#region node_modules/maath/dist/triangle-b62b9067.esm.js function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) _construct = Reflect.construct; else _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var instance = new (Function.bind.apply(Parent, a))(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; return _construct.apply(null, arguments); } function triangleDeterminant(triangle) { var _triangle$4 = _slicedToArray(triangle[0], 2), x1 = _triangle$4[0], y1 = _triangle$4[1]; var _triangle$5 = _slicedToArray(triangle[1], 2), x2 = _triangle$5[0], y2 = _triangle$5[1]; var _triangle$6 = _slicedToArray(triangle[2], 2), x3 = _triangle$6[0], y3 = _triangle$6[1]; return determinant3(x1, y1, 1, x2, y2, 1, x3, y3, 1); } /** * Uses triangle area determinant to check if 3 points are collinear. * If they are, they can't make a triangle, so the determinant will be 0! * * 0 1 2 * ─────■─────■─────■ * * * Fun fact, you can use this same determinant to check the order of the points in the triangle * * NOTE: Should this use a buffer instead? NOTE: Should this use a buffer instead? [x0, y0, x1, y1, x2, y2]? * */ function arePointsCollinear(points) { return triangleDeterminant(points) === 0; } var mv1 = new Vector2(); var mv2 = new Vector2(); /** ╱ ╲ ╱ ╲ ▕ ▏ right left * NOTE: Should this use a buffer instead? [x0, y0, x1, y1]? */ function doThreePointsMakeARight(points) { var _points$map2 = _slicedToArray(points.map(function(p) { if (Array.isArray(p)) return _construct(Vector2, _toConsumableArray(p)); return p; }), 3), p1 = _points$map2[0], p2 = _points$map2[1], p3 = _points$map2[2]; if (arePointsCollinear(points)) return false; var p2p1 = mv1.subVectors(p2, p1); return mv2.subVectors(p3, p1).cross(p2p1) > 0; } //#endregion //#region node_modules/maath/dist/misc-19a3ec46.esm.js /** * Clamps a value between a range. */ function clamp$1(value, min, max) { return Math.max(min, Math.min(max, value)); } function repeat(t, length) { return clamp$1(t - Math.floor(t / length) * length, 0, length); } function deltaAngle(current, target) { var delta = repeat(target - current, Math.PI * 2); if (delta > Math.PI) delta -= Math.PI * 2; return delta; } /** * Converts degrees to radians. */ function degToRad(degrees) { return degrees / 180 * Math.PI; } /** * Converts radians to degrees. */ function radToDeg(radians) { return radians * 180 / Math.PI; } function fibonacciOnSphere(buffer, _ref) { var _ref$radius = _ref.radius, radius = _ref$radius === void 0 ? 1 : _ref$radius; var samples = buffer.length / 3; var offset = 2 / samples; var increment = Math.PI * .7639320225000001; for (var i = 0; i < buffer.length; i += 3) { var y = i * offset - 1 + offset / 2; var distance = Math.sqrt(1 - Math.pow(y, 2)); var phi = i % samples * increment; var x = Math.cos(phi) * distance; var z = Math.sin(phi) * distance; buffer[i] = x * radius; buffer[i + 1] = y * radius; buffer[i + 2] = z * radius; } } function vectorEquals(a, b) { var eps = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : Number.EPSILON; return Math.abs(a.x - b.x) < eps && Math.abs(a.y - b.y) < eps && Math.abs(a.z - b.z) < eps; } /** * Sorts vectors in lexicographic order, works with both v2 and v3 * * Use as: * const sorted = arrayOfVectors.sort(lexicographicOrder) */ function lexicographic(a, b) { if (a.x === b.x) { if (typeof a.z !== "undefined") { if (a.y === b.y) return a.z - b.z; } return a.y - b.y; } return a.x - b.x; } /** * Convex Hull * * Returns an array of 2D Vectors representing the convex hull of a set of 2D Vectors */ /** * Calculate the convex hull of a set of points */ function convexHull(_points) { var points = _points.sort(lexicographic); var lUpper = [points[0], points[1]]; for (var i = 2; i < points.length; i++) { lUpper.push(points[i]); while (lUpper.length > 2 && doThreePointsMakeARight(_toConsumableArray(lUpper.slice(-3)))) lUpper.splice(lUpper.length - 2, 1); } var lLower = [points[points.length - 1], points[points.length - 2]]; for (var _i = points.length - 3; _i >= 0; _i--) { lLower.push(points[_i]); while (lLower.length > 2 && doThreePointsMakeARight(_toConsumableArray(lLower.slice(-3)))) lLower.splice(lLower.length - 2, 1); } lLower.splice(0, 1); lLower.splice(lLower.length - 1, 1); return [].concat(lUpper, lLower); } function remap(x, _ref2, _ref3) { var _ref4 = _slicedToArray(_ref2, 2), low1 = _ref4[0], high1 = _ref4[1]; var _ref5 = _slicedToArray(_ref3, 2), low2 = _ref5[0], high2 = _ref5[1]; return low2 + (x - low1) * (high2 - low2) / (high1 - low1); } /** * * https://www.desmos.com/calculator/vsnmlaljdu * * Ease-in-out, goes to -Infinite before 0 and Infinite after 1 * * @param t * @returns */ function fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); } /** * * Returns the result of linearly interpolating between input A and input B by input T. * * @param v0 * @param v1 * @param t * @returns */ function lerp(v0, v1, t) { return v0 * (1 - t) + v1 * t; } /** * * Returns the linear parameter that produces the interpolant specified by input T within the range of input A to input B. * * @param v0 * @param v1 * @param t * @returns */ function inverseLerp(v0, v1, t) { return (t - v0) / (v1 - v0); } /** * */ function normalize(x, y, z) { var m = Math.sqrt(x * x + y * y + z * z); return [ x / m, y / m, z / m ]; } /** * */ function pointOnCubeToPointOnSphere(x, y, z) { var x2 = x * x; var y2 = y * y; var z2 = z * z; return [ x * Math.sqrt(1 - (y2 + z2) / 2 + y2 * z2 / 3), y * Math.sqrt(1 - (z2 + x2) / 2 + z2 * x2 / 3), z * Math.sqrt(1 - (x2 + y2) / 2 + x2 * y2 / 3) ]; } /** * Give two unit vectors a and b, returns the transformation matrix that rotates a onto b. * * */ function rotateVectorOnVector(a, b) { var v = new Vector3().crossVectors(a, b); var c = a.dot(b); var i = new Matrix3().identity(); var vx = new Matrix3().set(0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0); var vxsquared = new Matrix3().multiplyMatrices(vx, vx).multiplyScalar(1 / (1 + c)); return matrixSum3(matrixSum3(i, vx), vxsquared); } function pointToCoordinate(x, y, z) { return [Math.asin(y), Math.atan2(x, -z)]; } function coordinateToPoint(lat, lon) { var y = Math.sin(lat); var r = Math.cos(lat); return [ Math.sin(lon) * r, y, -Math.cos(lon) * r ]; } /** * Given a plane and a segment, return the intersection point if it exists or null it doesn't. */ function planeSegmentIntersection(plane, segment) { var _segment = _slicedToArray(segment, 2), a = _segment[0], b = _segment[1]; var matrix = rotateVectorOnVector(plane.normal, new Vector3(0, 1, 0)); var t = inverseLerp(a.clone().applyMatrix3(matrix).y, b.clone().applyMatrix3(matrix).y, 0); return new Vector3().lerpVectors(a, b, t); } /** * Given a plane and a point, return the distance. */ function pointToPlaneDistance(p, plane) { return plane.normal.dot(p); } function getIndexFrom3D(coords, sides) { var _coords = _slicedToArray(coords, 3), ix = _coords[0], iy = _coords[1], iz = _coords[2]; var _sides = _slicedToArray(sides, 2), rx = _sides[0], ry = _sides[1]; return iz * rx * ry + iy * rx + ix; } function get3DFromIndex(index, size) { var _size = _slicedToArray(size, 2), rx = _size[0]; var a = rx * _size[1]; var z = index / a; var b = index - a * z; var y = b / rx; return [ b % rx, y, z ]; } function getIndexFrom2D(coords, size) { return coords[0] + size[0] * coords[1]; } function get2DFromIndex(index, columns) { return [index % columns, Math.floor(index / columns)]; } var misc = /*#__PURE__*/ Object.freeze({ __proto__: null, clamp: clamp$1, repeat, deltaAngle, degToRad, radToDeg, fibonacciOnSphere, vectorEquals, lexicographic, convexHull, remap, fade, lerp, inverseLerp, normalize, pointOnCubeToPointOnSphere, rotateVectorOnVector, pointToCoordinate, coordinateToPoint, planeSegmentIntersection, pointToPlaneDistance, getIndexFrom3D, get3DFromIndex, getIndexFrom2D, get2DFromIndex }); //#endregion //#region node_modules/maath/dist/classCallCheck-9098b006.esm.js function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); } //#endregion //#region node_modules/maath/dist/index-0332b2ed.esm.js var Grad = function Grad(x, y, z) { var _this = this; _classCallCheck(this, Grad); _defineProperty$1(this, "dot2", function(x, y) { return _this.x * x + _this.y * y; }); _defineProperty$1(this, "dot3", function(x, y, z) { return _this.x * x + _this.y * y + _this.z * z; }); this.x = x; this.y = y; this.z = z; }; var grad3 = [ new Grad(1, 1, 0), new Grad(-1, 1, 0), new Grad(1, -1, 0), new Grad(-1, -1, 0), new Grad(1, 0, 1), new Grad(-1, 0, 1), new Grad(1, 0, -1), new Grad(-1, 0, -1), new Grad(0, 1, 1), new Grad(0, -1, 1), new Grad(0, 1, -1), new Grad(0, -1, -1) ]; var p = [ 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 ]; var perm = new Array(512); var gradP = new Array(512); (function seed(_seed) { if (_seed > 0 && _seed < 1) _seed *= 65536; _seed = Math.floor(_seed); if (_seed < 256) _seed |= _seed << 8; for (var i = 0; i < 256; i++) { var v; if (i & 1) v = p[i] ^ _seed & 255; else v = p[i] ^ _seed >> 8 & 255; perm[i] = perm[i + 256] = v; gradP[i] = gradP[i + 256] = grad3[v % 12]; } })(0); .5 * (Math.sqrt(3) - 1); (3 - Math.sqrt(3)) / 6; Math.PI * 2; function normalizeSeed(seed) { if (typeof seed === "number") seed = Math.abs(seed); else if (typeof seed === "string") { var string = seed; seed = 0; for (var i = 0; i < string.length; i++) seed = (seed + (i + 1) * (string.charCodeAt(i) % 96)) % 2147483647; } if (seed === 0) seed = 311; return seed; } function lcgRandom(seed) { var state = normalizeSeed(seed); return function() { var result = state * 48271 % 2147483647; state = result; return result / 2147483647; }; } new function Generator(_seed) { var _this = this; _classCallCheck(this, Generator); _defineProperty$1(this, "seed", 0); _defineProperty$1(this, "init", function(seed) { _this.seed = seed; _this.value = lcgRandom(seed); }); _defineProperty$1(this, "value", lcgRandom(this.seed)); this.init(_seed); }(Math.random()); //#endregion //#region node_modules/maath/dist/easing-0f4db1c0.esm.js var rsqw = function rsqw(t) { var delta = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : .01; var a = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 1; var f = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : 1 / (2 * Math.PI); return a / Math.atan(1 / delta) * Math.atan(Math.sin(2 * Math.PI * t * f) / delta); }; var exp = function exp(t) { return 1 / (1 + t + .48 * t * t + .235 * t * t * t); }; var linear = function linear(t) { return t; }; var sine = { "in": function _in(x) { return 1 - Math.cos(x * Math.PI / 2); }, out: function out(x) { return Math.sin(x * Math.PI / 2); }, inOut: function inOut(x) { return -(Math.cos(Math.PI * x) - 1) / 2; } }; var cubic = { "in": function _in(x) { return x * x * x; }, out: function out(x) { return 1 - Math.pow(1 - x, 3); }, inOut: function inOut(x) { return x < .5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2; } }; var quint = { "in": function _in(x) { return x * x * x * x * x; }, out: function out(x) { return 1 - Math.pow(1 - x, 5); }, inOut: function inOut(x) { return x < .5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2; } }; var circ = { "in": function _in(x) { return 1 - Math.sqrt(1 - Math.pow(x, 2)); }, out: function out(x) { return Math.sqrt(1 - Math.pow(x - 1, 2)); }, inOut: function inOut(x) { return x < .5 ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2; } }; var quart = { "in": function _in(t) { return t * t * t * t; }, out: function out(t) { return 1 - --t * t * t * t; }, inOut: function inOut(t) { return t < .5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t; } }; var expo = { "in": function _in(x) { return x === 0 ? 0 : Math.pow(2, 10 * x - 10); }, out: function out(x) { return x === 1 ? 1 : 1 - Math.pow(2, -10 * x); }, inOut: function inOut(x) { return x === 0 ? 0 : x === 1 ? 1 : x < .5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2; } }; /** * Damp, based on Game Programming Gems 4 Chapter 1.10 * Return value indicates whether the animation is still running. */ function damp(current, prop, target) { var smoothTime = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : .25; var delta = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : .01; var maxSpeed = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : Infinity; var easing = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : exp; var eps = arguments.length > 7 && arguments[7] !== void 0 ? arguments[7] : .001; var vel = "velocity_" + prop; if (current.__damp === void 0) current.__damp = {}; if (current.__damp[vel] === void 0) current.__damp[vel] = 0; if (Math.abs(current[prop] - target) <= eps) { current[prop] = target; return false; } smoothTime = Math.max(1e-4, smoothTime); var omega = 2 / smoothTime; var t = easing(omega * delta); var change = current[prop] - target; var originalTo = target; var maxChange = maxSpeed * smoothTime; change = Math.min(Math.max(change, -maxChange), maxChange); target = current[prop] - change; var temp = (current.__damp[vel] + omega * change) * delta; current.__damp[vel] = (current.__damp[vel] - omega * temp) * t; var output = target + (change + temp) * t; if (originalTo - current[prop] > 0 === output > originalTo) { output = originalTo; current.__damp[vel] = (output - originalTo) / delta; } current[prop] = output; return true; } /** * DampLookAt */ var isCamera = function isCamera(v) { return v && v.isCamera; }; var isLight$1 = function isLight(v) { return v && v.isLight; }; var vl3d = /*@__PURE__*/ new Vector3(); var _q1 = /*@__PURE__*/ new Quaternion(); var _q2 = /*@__PURE__*/ new Quaternion(); var _m1 = /*@__PURE__*/ new Matrix4(); var _position$1 = /*@__PURE__*/ new Vector3(); function dampLookAt(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (typeof target === "number") vl3d.setScalar(target); else if (Array.isArray(target)) vl3d.set(target[0], target[1], target[2]); else vl3d.copy(target); var parent = current.parent; current.updateWorldMatrix(true, false); _position$1.setFromMatrixPosition(current.matrixWorld); if (isCamera(current) || isLight$1(current)) _m1.lookAt(_position$1, vl3d, current.up); else _m1.lookAt(vl3d, _position$1, current.up); dampQ(current.quaternion, _q2.setFromRotationMatrix(_m1), smoothTime, delta, maxSpeed, easing, eps); if (parent) { _m1.extractRotation(parent.matrixWorld); _q1.setFromRotationMatrix(_m1); dampQ(current.quaternion, _q2.copy(current.quaternion).premultiply(_q1.invert()), smoothTime, delta, maxSpeed, easing, eps); } } /** * DampAngle, with a shortest-path */ function dampAngle(current, prop, target, smoothTime, delta, maxSpeed, easing, eps) { return damp(current, prop, current[prop] + deltaAngle(current[prop], target), smoothTime, delta, maxSpeed, easing, eps); } /** * Vector2D Damp */ var v2d = /*@__PURE__*/ new Vector2(); var a2, b2; function damp2(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (typeof target === "number") v2d.setScalar(target); else if (Array.isArray(target)) v2d.set(target[0], target[1]); else v2d.copy(target); a2 = damp(current, "x", v2d.x, smoothTime, delta, maxSpeed, easing, eps); b2 = damp(current, "y", v2d.y, smoothTime, delta, maxSpeed, easing, eps); return a2 || b2; } /** * Vector3D Damp */ var v3d = /*@__PURE__*/ new Vector3(); var a3, b3, c3; function damp3(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (typeof target === "number") v3d.setScalar(target); else if (Array.isArray(target)) v3d.set(target[0], target[1], target[2]); else v3d.copy(target); a3 = damp(current, "x", v3d.x, smoothTime, delta, maxSpeed, easing, eps); b3 = damp(current, "y", v3d.y, smoothTime, delta, maxSpeed, easing, eps); c3 = damp(current, "z", v3d.z, smoothTime, delta, maxSpeed, easing, eps); return a3 || b3 || c3; } /** * Vector4D Damp */ var v4d = /*@__PURE__*/ new Vector4(); var a4, b4, c4, d4; function damp4(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (typeof target === "number") v4d.setScalar(target); else if (Array.isArray(target)) v4d.set(target[0], target[1], target[2], target[3]); else v4d.copy(target); a4 = damp(current, "x", v4d.x, smoothTime, delta, maxSpeed, easing, eps); b4 = damp(current, "y", v4d.y, smoothTime, delta, maxSpeed, easing, eps); c4 = damp(current, "z", v4d.z, smoothTime, delta, maxSpeed, easing, eps); d4 = damp(current, "w", v4d.w, smoothTime, delta, maxSpeed, easing, eps); return a4 || b4 || c4 || d4; } /** * Euler Damp */ var rot = /*@__PURE__*/ new Euler(); var aE, bE, cE; function dampE(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (Array.isArray(target)) rot.set(target[0], target[1], target[2], target[3]); else rot.copy(target); aE = dampAngle(current, "x", rot.x, smoothTime, delta, maxSpeed, easing, eps); bE = dampAngle(current, "y", rot.y, smoothTime, delta, maxSpeed, easing, eps); cE = dampAngle(current, "z", rot.z, smoothTime, delta, maxSpeed, easing, eps); return aE || bE || cE; } /** * Color Damp */ var col$1 = /*@__PURE__*/ new Color(); var aC, bC, cC; function dampC(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (target instanceof Color) col$1.copy(target); else if (Array.isArray(target)) col$1.setRGB(target[0], target[1], target[2]); else col$1.set(target); aC = damp(current, "r", col$1.r, smoothTime, delta, maxSpeed, easing, eps); bC = damp(current, "g", col$1.g, smoothTime, delta, maxSpeed, easing, eps); cC = damp(current, "b", col$1.b, smoothTime, delta, maxSpeed, easing, eps); return aC || bC || cC; } /** * Quaternion Damp * https://gist.github.com/maxattack/4c7b4de00f5c1b95a33b * Copyright 2016 Max Kaufmann (max.kaufmann@gmail.com) * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var qt = /*@__PURE__*/ new Quaternion(); var v4result = /*@__PURE__*/ new Vector4(); var v4velocity = /*@__PURE__*/ new Vector4(); var v4error = /*@__PURE__*/ new Vector4(); var aQ, bQ, cQ, dQ; function dampQ(current, target, smoothTime, delta, maxSpeed, easing, eps) { var cur = current; if (Array.isArray(target)) qt.set(target[0], target[1], target[2], target[3]); else qt.copy(target); var multi = current.dot(qt) > 0 ? 1 : -1; qt.x *= multi; qt.y *= multi; qt.z *= multi; qt.w *= multi; aQ = damp(current, "x", qt.x, smoothTime, delta, maxSpeed, easing, eps); bQ = damp(current, "y", qt.y, smoothTime, delta, maxSpeed, easing, eps); cQ = damp(current, "z", qt.z, smoothTime, delta, maxSpeed, easing, eps); dQ = damp(current, "w", qt.w, smoothTime, delta, maxSpeed, easing, eps); v4result.set(current.x, current.y, current.z, current.w).normalize(); v4velocity.set(cur.__damp.velocity_x, cur.__damp.velocity_y, cur.__damp.velocity_z, cur.__damp.velocity_w); v4error.copy(v4result).multiplyScalar(v4velocity.dot(v4result) / v4result.dot(v4result)); cur.__damp.velocity_x -= v4error.x; cur.__damp.velocity_y -= v4error.y; cur.__damp.velocity_z -= v4error.z; cur.__damp.velocity_w -= v4error.w; current.set(v4result.x, v4result.y, v4result.z, v4result.w); return aQ || bQ || cQ || dQ; } /** * Spherical Damp */ var spherical = /*@__PURE__*/ new Spherical(); var aS, bS, cS; function dampS(current, target, smoothTime, delta, maxSpeed, easing, eps) { if (Array.isArray(target)) spherical.set(target[0], target[1], target[2]); else spherical.copy(target); aS = damp(current, "radius", spherical.radius, smoothTime, delta, maxSpeed, easing, eps); bS = dampAngle(current, "phi", spherical.phi, smoothTime, delta, maxSpeed, easing, eps); cS = dampAngle(current, "theta", spherical.theta, smoothTime, delta, maxSpeed, easing, eps); return aS || bS || cS; } /** * Matrix4 Damp */ var mat = /*@__PURE__*/ new Matrix4(); var mPos = /*@__PURE__*/ new Vector3(); var mRot = /*@__PURE__*/ new Quaternion(); var mSca = /*@__PURE__*/ new Vector3(); var aM, bM, cM; function dampM(current, target, smoothTime, delta, maxSpeed, easing, eps) { var cur = current; if (cur.__damp === void 0) { cur.__damp = { position: new Vector3(), rotation: new Quaternion(), scale: new Vector3() }; current.decompose(cur.__damp.position, cur.__damp.rotation, cur.__damp.scale); } if (Array.isArray(target)) mat.set.apply(mat, _toConsumableArray(target)); else mat.copy(target); mat.decompose(mPos, mRot, mSca); aM = damp3(cur.__damp.position, mPos, smoothTime, delta, maxSpeed, easing, eps); bM = dampQ(cur.__damp.rotation, mRot, smoothTime, delta, maxSpeed, easing, eps); cM = damp3(cur.__damp.scale, mSca, smoothTime, delta, maxSpeed, easing, eps); current.compose(cur.__damp.position, cur.__damp.rotation, cur.__damp.scale); return aM || bM || cM; } var easing = /*#__PURE__*/ Object.freeze({ __proto__: null, rsqw, exp, linear, sine, cubic, quint, circ, quart, expo, damp, dampLookAt, dampAngle, damp2, damp3, damp4, dampE, dampC, dampQ, dampS, dampM }); //#endregion //#region node_modules/@react-three/drei/web/ScrollControls.js var context$9 = /* @__PURE__ */ import_react.createContext(null); function useScroll() { return import_react.useContext(context$9); } function ScrollControls({ eps = 1e-5, enabled = true, infinite, horizontal, pages = 1, distance = 1, damping = .25, maxSpeed = Infinity, prepend = false, style = {}, children }) { const { get, setEvents, gl, size, invalidate, events } = useThree(); const [el] = import_react.useState(() => document.createElement("div")); const [fill] = import_react.useState(() => document.createElement("div")); const [fixed] = import_react.useState(() => document.createElement("div")); const target = gl.domElement.parentNode; const scroll = import_react.useRef(0); const state = import_react.useMemo(() => { return { el, eps, fill, fixed, horizontal, damping, offset: 0, delta: 0, scroll, pages, range(from, distance, margin = 0) { const start = from - margin; const end = start + distance + margin * 2; return this.offset < start ? 0 : this.offset > end ? 1 : (this.offset - start) / (end - start); }, curve(from, distance, margin = 0) { return Math.sin(this.range(from, distance, margin) * Math.PI); }, visible(from, distance, margin = 0) { const start = from - margin; const end = start + distance + margin * 2; return this.offset >= start && this.offset <= end; } }; }, [ eps, damping, horizontal, pages ]); import_react.useEffect(() => { el.style.position = "absolute"; el.style.width = "100%"; el.style.height = "100%"; el.style[horizontal ? "overflowX" : "overflowY"] = "auto"; el.style[horizontal ? "overflowY" : "overflowX"] = "hidden"; el.style.top = "0px"; el.style.left = "0px"; for (const key in style) el.style[key] = style[key]; fixed.style.position = "sticky"; fixed.style.top = "0px"; fixed.style.left = "0px"; fixed.style.width = "100%"; fixed.style.height = "100%"; fixed.style.overflow = "hidden"; el.appendChild(fixed); fill.style.height = horizontal ? "100%" : `${pages * distance * 100}%`; fill.style.width = horizontal ? `${pages * distance * 100}%` : "100%"; fill.style.pointerEvents = "none"; el.appendChild(fill); if (prepend) target.prepend(el); else target.appendChild(el); el[horizontal ? "scrollLeft" : "scrollTop"] = 1; const oldTarget = events.connected || gl.domElement; requestAnimationFrame(() => events.connect == null ? void 0 : events.connect(el)); const oldCompute = get().events.compute; setEvents({ compute(event, state) { const { left, top } = target.getBoundingClientRect(); const offsetX = event.clientX - left; const offsetY = event.clientY - top; state.pointer.set(offsetX / state.size.width * 2 - 1, -(offsetY / state.size.height) * 2 + 1); state.raycaster.setFromCamera(state.pointer, state.camera); } }); return () => { target.removeChild(el); setEvents({ compute: oldCompute }); events.connect == null || events.connect(oldTarget); }; }, [ pages, distance, horizontal, el, fill, fixed, target ]); import_react.useEffect(() => { if (events.connected === el) { const containerLength = size[horizontal ? "width" : "height"]; const scrollLength = el[horizontal ? "scrollWidth" : "scrollHeight"]; const scrollThreshold = scrollLength - containerLength; let current = 0; let disableScroll = true; let firstRun = true; const onScroll = () => { if (!enabled || firstRun) return; invalidate(); current = el[horizontal ? "scrollLeft" : "scrollTop"]; scroll.current = current / scrollThreshold; if (infinite) { if (!disableScroll) { if (current >= scrollThreshold) { const damp = 1 - state.offset; el[horizontal ? "scrollLeft" : "scrollTop"] = 1; scroll.current = state.offset = -damp; disableScroll = true; } else if (current <= 0) { const damp = 1 + state.offset; el[horizontal ? "scrollLeft" : "scrollTop"] = scrollLength; scroll.current = state.offset = damp; disableScroll = true; } } if (disableScroll) setTimeout(() => disableScroll = false, 40); } }; el.addEventListener("scroll", onScroll, { passive: true }); requestAnimationFrame(() => firstRun = false); const onWheel = (e) => el.scrollLeft += e.deltaY / 2; if (horizontal) el.addEventListener("wheel", onWheel, { passive: true }); return () => { el.removeEventListener("scroll", onScroll); if (horizontal) el.removeEventListener("wheel", onWheel); }; } }, [ el, events, size, infinite, state, invalidate, horizontal, enabled ]); let last = 0; useFrame((_, delta) => { last = state.offset; easing.damp(state, "offset", scroll.current, damping, delta, maxSpeed, void 0, eps); easing.damp(state, "delta", Math.abs(last - state.offset), damping, delta, maxSpeed, void 0, eps); if (state.delta > eps) invalidate(); }); return /*#__PURE__*/ import_react.createElement(context$9.Provider, { value: state }, children); } var ScrollCanvas = /* @__PURE__ */ import_react.forwardRef(({ children }, ref) => { const group = import_react.useRef(null); import_react.useImperativeHandle(ref, () => group.current, []); const state = useScroll(); const { width, height } = useThree((state) => state.viewport); useFrame(() => { group.current.position.x = state.horizontal ? -width * (state.pages - 1) * state.offset : 0; group.current.position.y = state.horizontal ? 0 : height * (state.pages - 1) * state.offset; }); return /*#__PURE__*/ import_react.createElement("group", { ref: group }, children); }); var ScrollHtml = /*#__PURE__*/ import_react.forwardRef(({ children, style, ...props }, ref) => { const state = useScroll(); const group = import_react.useRef(null); import_react.useImperativeHandle(ref, () => group.current, []); const { width, height } = useThree((state) => state.size); const fiberState = import_react.useContext(context$10); const root = import_react.useMemo(() => import_client.createRoot(state.fixed), [state.fixed]); useFrame(() => { if (state.delta > state.eps) group.current.style.transform = `translate3d(${state.horizontal ? -width * (state.pages - 1) * state.offset : 0}px,${state.horizontal ? 0 : height * (state.pages - 1) * -state.offset}px,0)`; }); root.render(/*#__PURE__*/ import_react.createElement("div", _extends$1({ ref: group, style: { ...style, position: "absolute", top: 0, left: 0, willChange: "transform" } }, props), /*#__PURE__*/ import_react.createElement(context$9.Provider, { value: state }, /*#__PURE__*/ import_react.createElement(context$10.Provider, { value: fiberState }, children)))); return null; }); var Scroll = /* @__PURE__ */ import_react.forwardRef(({ html, ...props }, ref) => { const El = html ? ScrollHtml : ScrollCanvas; return /*#__PURE__*/ import_react.createElement(El, _extends$1({ ref }, props)); }); //#endregion //#region node_modules/@react-three/drei/web/PresentationControls.js function PresentationControls({ enabled = true, snap, global, domElement, cursor = true, children, speed = 1, rotation = [ 0, 0, 0 ], zoom = 1, polar = [0, Math.PI / 2], azimuth = [-Infinity, Infinity], damping = .25 }) { const events = useThree((state) => state.events); const gl = useThree((state) => state.gl); const explDomElement = domElement || events.connected || gl.domElement; const { size } = useThree(); const rPolar = import_react.useMemo(() => [rotation[0] + polar[0], rotation[0] + polar[1]], [ rotation[0], polar[0], polar[1] ]); const rAzimuth = import_react.useMemo(() => [rotation[1] + azimuth[0], rotation[1] + azimuth[1]], [ rotation[1], azimuth[0], azimuth[1] ]); const rInitial = import_react.useMemo(() => [ MathUtils.clamp(rotation[0], ...rPolar), MathUtils.clamp(rotation[1], ...rAzimuth), rotation[2] ], [ rotation[0], rotation[1], rotation[2], rPolar, rAzimuth ]); import_react.useEffect(() => { if (global && cursor && enabled) { explDomElement.style.cursor = "grab"; gl.domElement.style.cursor = ""; return () => { explDomElement.style.cursor = "default"; gl.domElement.style.cursor = "default"; }; } }, [ global, cursor, explDomElement, enabled ]); const [animation] = import_react.useState({ scale: 1, rotation: rInitial, damping }); const ref = import_react.useRef(null); useFrame((state, delta) => { easing.damp3(ref.current.scale, animation.scale, animation.damping, delta); easing.dampE(ref.current.rotation, animation.rotation, animation.damping, delta); }); const bind = useGesture({ onHover: ({ last }) => { if (cursor && !global && enabled) explDomElement.style.cursor = last ? "auto" : "grab"; }, onDrag: ({ down, delta: [x, y], memo: [oldY, oldX] = animation.rotation || rInitial }) => { if (!enabled) return [y, x]; if (cursor) explDomElement.style.cursor = down ? "grabbing" : "grab"; x = MathUtils.clamp(oldX + x / size.width * Math.PI * speed, ...rAzimuth); y = MathUtils.clamp(oldY + y / size.height * Math.PI * speed, ...rPolar); animation.scale = down && y > rPolar[1] / 2 ? zoom : 1; animation.rotation = snap && !down ? rInitial : [ y, x, 0 ]; animation.damping = snap && !down && typeof snap !== "boolean" ? snap : damping; return [y, x]; } }, { target: global ? explDomElement : void 0 }); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, bind == null ? void 0 : bind()), children); } //#endregion //#region node_modules/zustand/esm/middleware.mjs var subscribeWithSelectorImpl = (fn) => (set, get, api) => { const origSubscribe = api.subscribe; api.subscribe = ((selector, optListener, options) => { let listener = selector; if (optListener) { const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is; let currentSlice = selector(api.getState()); listener = (state) => { const nextSlice = selector(state); if (!equalityFn(currentSlice, nextSlice)) { const previousSlice = currentSlice; optListener(currentSlice = nextSlice, previousSlice); } }; if (options == null ? void 0 : options.fireImmediately) optListener(currentSlice, currentSlice); } return origSubscribe(listener); }); return fn(set, get, api); }; var subscribeWithSelector = subscribeWithSelectorImpl; //#endregion //#region node_modules/@react-three/drei/web/KeyboardControls.js var context$8 = /* @__PURE__ */ import_react.createContext(null); function KeyboardControls({ map, children, onChange, domElement }) { const key = map.map((item) => item.name + item.keys).join("-"); const useControls = import_react.useMemo(() => { return create$2(subscribeWithSelector(() => map.reduce((prev, cur) => ({ ...prev, [cur.name]: false }), {}))); }, [key]); const api = import_react.useMemo(() => [ useControls.subscribe, useControls.getState, useControls ], [key]); const set = useControls.setState; import_react.useEffect(() => { const keyMap = map.map(({ name, keys, up }) => ({ keys, up, fn: (value) => { set({ [name]: value }); if (onChange) onChange(name, value, api[1]()); } })).reduce((out, { keys, fn, up = true }) => { keys.forEach((key) => out[key] = { fn, pressed: false, up }); return out; }, {}); const downHandler = ({ key, code }) => { const obj = keyMap[key] || keyMap[code]; if (!obj) return; const { fn, pressed, up } = obj; obj.pressed = true; if (up || !pressed) fn(true); }; const upHandler = ({ key, code }) => { const obj = keyMap[key] || keyMap[code]; if (!obj) return; const { fn, up } = obj; obj.pressed = false; if (up) fn(false); }; const source = domElement || window; source.addEventListener("keydown", downHandler, { passive: true }); source.addEventListener("keyup", upHandler, { passive: true }); return () => { source.removeEventListener("keydown", downHandler); source.removeEventListener("keyup", upHandler); }; }, [domElement, key]); return /*#__PURE__*/ import_react.createElement(context$8.Provider, { value: api, children }); } function useKeyboardControls(sel) { const [sub, get, store] = import_react.useContext(context$8); if (sel) return store(sel); else return [sub, get]; } //#endregion //#region node_modules/three-stdlib/_polyfill/constants.js var version$2 = /* @__PURE__ */ (() => parseInt("184".replace(/\D+/g, "")))(); //#endregion //#region node_modules/three-stdlib/_polyfill/uv1.js var UV1 = version$2 >= 125 ? "uv1" : "uv2"; //#endregion //#region node_modules/three-stdlib/modifiers/CurveModifier.js var __defProp$19 = Object.defineProperty; var __defNormalProp$19 = (obj, key, value) => key in obj ? __defProp$19(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$19 = (obj, key, value) => { __defNormalProp$19(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var CHANNELS = 4; var TEXTURE_WIDTH = 1024; var TEXTURE_HEIGHT = 4; var initSplineTexture = (numberOfCurves = 1) => { const dataTexture = new DataTexture(new Float32Array(TEXTURE_WIDTH * TEXTURE_HEIGHT * numberOfCurves * CHANNELS), TEXTURE_WIDTH, TEXTURE_HEIGHT * numberOfCurves, RGBAFormat, FloatType); dataTexture.wrapS = RepeatWrapping; dataTexture.wrapT = RepeatWrapping; dataTexture.magFilter = NearestFilter; dataTexture.needsUpdate = true; return dataTexture; }; var updateSplineTexture = (texture, splineCurve, offset = 0) => { const numberOfPoints = Math.floor(TEXTURE_WIDTH * (TEXTURE_HEIGHT / 4)); splineCurve.arcLengthDivisions = numberOfPoints / 2; splineCurve.updateArcLengths(); const points = splineCurve.getSpacedPoints(numberOfPoints); const frenetFrames = splineCurve.computeFrenetFrames(numberOfPoints, true); for (let i = 0; i < numberOfPoints; i++) { const rowOffset = Math.floor(i / TEXTURE_WIDTH); const rowIndex = i % TEXTURE_WIDTH; let pt = points[i]; setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 0 + rowOffset + TEXTURE_HEIGHT * offset); pt = frenetFrames.tangents[i]; setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 1 + rowOffset + TEXTURE_HEIGHT * offset); pt = frenetFrames.normals[i]; setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 2 + rowOffset + TEXTURE_HEIGHT * offset); pt = frenetFrames.binormals[i]; setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 3 + rowOffset + TEXTURE_HEIGHT * offset); } texture.needsUpdate = true; }; var setTextureValue = (texture, index, x, y, z, o) => { const { data } = texture.image; const i = CHANNELS * TEXTURE_WIDTH * o; data[index * CHANNELS + i + 0] = x; data[index * CHANNELS + i + 1] = y; data[index * CHANNELS + i + 2] = z; data[index * CHANNELS + i + 3] = 1; }; var getUniforms$1 = (splineTexture) => ({ spineTexture: { value: splineTexture }, pathOffset: { type: "f", value: 0 }, pathSegment: { type: "f", value: 1 }, spineOffset: { type: "f", value: 161 }, spineLength: { type: "f", value: 400 }, flow: { type: "i", value: 1 } }); function modifyShader(material, uniforms, numberOfCurves = 1) { if (material.__ok) return; material.__ok = true; material.onBeforeCompile = (shader) => { if (shader.__modified) return; shader.__modified = true; Object.assign(shader.uniforms, uniforms); shader.vertexShader = ` uniform sampler2D spineTexture; uniform float pathOffset; uniform float pathSegment; uniform float spineOffset; uniform float spineLength; uniform int flow; float textureLayers = ${TEXTURE_HEIGHT * numberOfCurves}.; float textureStacks = ${TEXTURE_HEIGHT / 4}.; ${shader.vertexShader} `.replace("#include ", "").replace("#include ", "").replace("#include ", "").replace(/void\s*main\s*\(\)\s*\{/, ` void main() { #include vec4 worldPos = modelMatrix * vec4(position, 1.); bool bend = flow > 0; float xWeight = bend ? 0. : 1.; #ifdef USE_INSTANCING float pathOffsetFromInstanceMatrix = instanceMatrix[3][2]; float spineLengthFromInstanceMatrix = instanceMatrix[3][0]; float spinePortion = bend ? (worldPos.x + spineOffset) / spineLengthFromInstanceMatrix : 0.; float mt = (spinePortion * pathSegment + pathOffset + pathOffsetFromInstanceMatrix)*textureStacks; #else float spinePortion = bend ? (worldPos.x + spineOffset) / spineLength : 0.; float mt = (spinePortion * pathSegment + pathOffset)*textureStacks; #endif mt = mod(mt, textureStacks); float rowOffset = floor(mt); #ifdef USE_INSTANCING rowOffset += instanceMatrix[3][1] * ${TEXTURE_HEIGHT}.; #endif vec3 spinePos = texture2D(spineTexture, vec2(mt, (0. + rowOffset + 0.5) / textureLayers)).xyz; vec3 a = texture2D(spineTexture, vec2(mt, (1. + rowOffset + 0.5) / textureLayers)).xyz; vec3 b = texture2D(spineTexture, vec2(mt, (2. + rowOffset + 0.5) / textureLayers)).xyz; vec3 c = texture2D(spineTexture, vec2(mt, (3. + rowOffset + 0.5) / textureLayers)).xyz; mat3 basis = mat3(a, b, c); vec3 transformed = basis * vec3(worldPos.x * xWeight, worldPos.y * 1., worldPos.z * 1.) + spinePos; vec3 transformedNormal = normalMatrix * (basis * objectNormal); `).replace("#include ", `vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 ); gl_Position = projectionMatrix * mvPosition;`); }; } var Flow = class { /** * @param {Mesh} mesh The mesh to clone and modify to bend around the curve * @param {number} numberOfCurves The amount of space that should preallocated for additional curves */ constructor(mesh, numberOfCurves = 1) { __publicField$19(this, "curveArray"); __publicField$19(this, "curveLengthArray"); __publicField$19(this, "object3D"); __publicField$19(this, "splineTexure"); __publicField$19(this, "uniforms"); const obj3D = mesh.clone(); const splineTexure = initSplineTexture(numberOfCurves); const uniforms = getUniforms$1(splineTexure); obj3D.traverse((child) => { if (child instanceof Mesh || child instanceof InstancedMesh) { child.material = child.material.clone(); modifyShader(child.material, uniforms, numberOfCurves); } }); this.curveArray = new Array(numberOfCurves); this.curveLengthArray = new Array(numberOfCurves); this.object3D = obj3D; this.splineTexure = splineTexure; this.uniforms = uniforms; } updateCurve(index, curve) { if (index >= this.curveArray.length) throw Error("Index out of range for Flow"); const curveLength = curve.getLength(); this.uniforms.spineLength.value = curveLength; this.curveLengthArray[index] = curveLength; this.curveArray[index] = curve; updateSplineTexture(this.splineTexure, curve, index); } moveAlongCurve(amount) { this.uniforms.pathOffset.value += amount; } }; //#endregion //#region node_modules/three-stdlib/utils/BufferGeometryUtils.js function mergeVertices(geometry, tolerance = 1e-4) { tolerance = Math.max(tolerance, Number.EPSILON); const hashToIndex = {}; const indices = geometry.getIndex(); const positions = geometry.getAttribute("position"); const vertexCount = indices ? indices.count : positions.count; let nextIndex = 0; const attributeNames = Object.keys(geometry.attributes); const attrArrays = {}; const morphAttrsArrays = {}; const newIndices = []; const getters = [ "getX", "getY", "getZ", "getW" ]; for (let i = 0, l = attributeNames.length; i < l; i++) { const name = attributeNames[i]; attrArrays[name] = []; const morphAttr = geometry.morphAttributes[name]; if (morphAttr) morphAttrsArrays[name] = new Array(morphAttr.length).fill(0).map(() => []); } const decimalShift = Math.log10(1 / tolerance); const shiftMultiplier = Math.pow(10, decimalShift); for (let i = 0; i < vertexCount; i++) { const index = indices ? indices.getX(i) : i; let hash = ""; for (let j = 0, l = attributeNames.length; j < l; j++) { const name = attributeNames[j]; const attribute = geometry.getAttribute(name); const itemSize = attribute.itemSize; for (let k = 0; k < itemSize; k++) hash += `${~~(attribute[getters[k]](index) * shiftMultiplier)},`; } if (hash in hashToIndex) newIndices.push(hashToIndex[hash]); else { for (let j = 0, l = attributeNames.length; j < l; j++) { const name = attributeNames[j]; const attribute = geometry.getAttribute(name); const morphAttr = geometry.morphAttributes[name]; const itemSize = attribute.itemSize; const newarray = attrArrays[name]; const newMorphArrays = morphAttrsArrays[name]; for (let k = 0; k < itemSize; k++) { const getterFunc = getters[k]; newarray.push(attribute[getterFunc](index)); if (morphAttr) for (let m = 0, ml = morphAttr.length; m < ml; m++) newMorphArrays[m].push(morphAttr[m][getterFunc](index)); } } hashToIndex[hash] = nextIndex; newIndices.push(nextIndex); nextIndex++; } } const result = geometry.clone(); for (let i = 0, l = attributeNames.length; i < l; i++) { const name = attributeNames[i]; const oldAttribute = geometry.getAttribute(name); const attribute = new BufferAttribute(new oldAttribute.array.constructor(attrArrays[name]), oldAttribute.itemSize, oldAttribute.normalized); result.setAttribute(name, attribute); if (name in morphAttrsArrays) for (let j = 0; j < morphAttrsArrays[name].length; j++) { const oldMorphAttribute = geometry.morphAttributes[name][j]; const morphAttribute = new BufferAttribute(new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]), oldMorphAttribute.itemSize, oldMorphAttribute.normalized); result.morphAttributes[name][j] = morphAttribute; } } result.setIndex(newIndices); return result; } function toTrianglesDrawMode(geometry, drawMode) { if (drawMode === 0) { console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles."); return geometry; } if (drawMode === 2 || drawMode === 1) { let index = geometry.getIndex(); if (index === null) { const indices = []; const position = geometry.getAttribute("position"); if (position !== void 0) { for (let i = 0; i < position.count; i++) indices.push(i); geometry.setIndex(indices); index = geometry.getIndex(); } else { console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible."); return geometry; } } const numberOfTriangles = index.count - 2; const newIndices = []; if (index) if (drawMode === 2) for (let i = 1; i <= numberOfTriangles; i++) { newIndices.push(index.getX(0)); newIndices.push(index.getX(i)); newIndices.push(index.getX(i + 1)); } else for (let i = 0; i < numberOfTriangles; i++) if (i % 2 === 0) { newIndices.push(index.getX(i)); newIndices.push(index.getX(i + 1)); newIndices.push(index.getX(i + 2)); } else { newIndices.push(index.getX(i + 2)); newIndices.push(index.getX(i + 1)); newIndices.push(index.getX(i)); } if (newIndices.length / 3 !== numberOfTriangles) console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles."); const newGeometry = geometry.clone(); newGeometry.setIndex(newIndices); newGeometry.clearGroups(); return newGeometry; } else { console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:", drawMode); return geometry; } } function toCreasedNormals(geometry, creaseAngle = Math.PI / 3) { const creaseDot = Math.cos(creaseAngle); const hashMultiplier = 1.0000000001 * 100; const verts = [ new Vector3(), new Vector3(), new Vector3() ]; const tempVec1 = new Vector3(); const tempVec2 = new Vector3(); const tempNorm = new Vector3(); const tempNorm2 = new Vector3(); function hashVertex(v) { return `${~~(v.x * hashMultiplier)},${~~(v.y * hashMultiplier)},${~~(v.z * hashMultiplier)}`; } const resultGeometry = geometry.index ? geometry.toNonIndexed() : geometry; const posAttr = resultGeometry.attributes.position; const vertexMap = {}; for (let i = 0, l = posAttr.count / 3; i < l; i++) { const i3 = 3 * i; const a = verts[0].fromBufferAttribute(posAttr, i3 + 0); const b = verts[1].fromBufferAttribute(posAttr, i3 + 1); const c = verts[2].fromBufferAttribute(posAttr, i3 + 2); tempVec1.subVectors(c, b); tempVec2.subVectors(a, b); const normal = new Vector3().crossVectors(tempVec1, tempVec2).normalize(); for (let n = 0; n < 3; n++) { const vert = verts[n]; const hash = hashVertex(vert); if (!(hash in vertexMap)) vertexMap[hash] = []; vertexMap[hash].push(normal); } } const normAttr = new BufferAttribute(new Float32Array(posAttr.count * 3), 3, false); for (let i = 0, l = posAttr.count / 3; i < l; i++) { const i3 = 3 * i; const a = verts[0].fromBufferAttribute(posAttr, i3 + 0); const b = verts[1].fromBufferAttribute(posAttr, i3 + 1); const c = verts[2].fromBufferAttribute(posAttr, i3 + 2); tempVec1.subVectors(c, b); tempVec2.subVectors(a, b); tempNorm.crossVectors(tempVec1, tempVec2).normalize(); for (let n = 0; n < 3; n++) { const vert = verts[n]; const otherNormals = vertexMap[hashVertex(vert)]; tempNorm2.set(0, 0, 0); for (let k = 0, lk = otherNormals.length; k < lk; k++) { const otherNorm = otherNormals[k]; if (tempNorm.dot(otherNorm) > creaseDot) tempNorm2.add(otherNorm); } tempNorm2.normalize(); normAttr.setXYZ(i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z); } } resultGeometry.setAttribute("normal", normAttr); return resultGeometry; } //#endregion //#region node_modules/three-stdlib/node_modules/fflate/esm/browser.js var u8 = Uint8Array, u16 = Uint16Array, u32 = Uint32Array; var fleb = new u8([ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0 ]); var fdeb = new u8([ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 ]); var clim = new u8([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); var freb = function(eb, start) { var b = new u16(31); for (var i = 0; i < 31; ++i) b[i] = start += 1 << eb[i - 1]; var r = new u32(b[30]); for (var i = 1; i < 30; ++i) for (var j = b[i]; j < b[i + 1]; ++j) r[j] = j - b[i] << 5 | i; return [b, r]; }; var _a = freb(fleb, 2), fl = _a[0], revfl = _a[1]; fl[28] = 258, revfl[258] = 28; var _b = freb(fdeb, 0), fd = _b[0]; _b[1]; var rev = new u16(32768); for (var i$2 = 0; i$2 < 32768; ++i$2) { var x = (i$2 & 43690) >>> 1 | (i$2 & 21845) << 1; x = (x & 52428) >>> 2 | (x & 13107) << 2; x = (x & 61680) >>> 4 | (x & 3855) << 4; rev[i$2] = ((x & 65280) >>> 8 | (x & 255) << 8) >>> 1; } var hMap = (function(cd, mb, r) { var s = cd.length; var i = 0; var l = new u16(mb); for (; i < s; ++i) ++l[cd[i] - 1]; var le = new u16(mb); for (i = 0; i < mb; ++i) le[i] = le[i - 1] + l[i - 1] << 1; var co; if (r) { co = new u16(1 << mb); var rvb = 15 - mb; for (i = 0; i < s; ++i) if (cd[i]) { var sv = i << 4 | cd[i]; var r_1 = mb - cd[i]; var v = le[cd[i] - 1]++ << r_1; for (var m = v | (1 << r_1) - 1; v <= m; ++v) co[rev[v] >>> rvb] = sv; } } else { co = new u16(s); for (i = 0; i < s; ++i) if (cd[i]) co[i] = rev[le[cd[i] - 1]++] >>> 15 - cd[i]; } return co; }); var flt = new u8(288); for (var i$2 = 0; i$2 < 144; ++i$2) flt[i$2] = 8; for (var i$2 = 144; i$2 < 256; ++i$2) flt[i$2] = 9; for (var i$2 = 256; i$2 < 280; ++i$2) flt[i$2] = 7; for (var i$2 = 280; i$2 < 288; ++i$2) flt[i$2] = 8; var fdt = new u8(32); for (var i$2 = 0; i$2 < 32; ++i$2) fdt[i$2] = 5; var flrm = /*#__PURE__*/ hMap(flt, 9, 1), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); var max = function(a) { var m = a[0]; for (var i = 1; i < a.length; ++i) if (a[i] > m) m = a[i]; return m; }; var bits = function(d, p, m) { var o = p / 8 | 0; return (d[o] | d[o + 1] << 8) >> (p & 7) & m; }; var bits16 = function(d, p) { var o = p / 8 | 0; return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7); }; var shft = function(p) { return (p / 8 | 0) + (p & 7 && 1); }; var slc = function(v, s, e) { if (s == null || s < 0) s = 0; if (e == null || e > v.length) e = v.length; var n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s); n.set(v.subarray(s, e)); return n; }; var inflt = function(dat, buf, st) { var sl = dat.length; if (!sl || st && !st.l && sl < 5) return buf || new u8(0); var noBuf = !buf || st; var noSt = !st || st.i; if (!st) st = {}; if (!buf) buf = new u8(sl * 3); var cbuf = function(l) { var bl = buf.length; if (l > bl) { var nbuf = new u8(Math.max(bl * 2, l)); nbuf.set(buf); buf = nbuf; } }; var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; var tbts = sl * 8; do { if (!lm) { st.f = final = bits(dat, pos, 1); var type = bits(dat, pos + 1, 3); pos += 3; if (!type) { var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l; if (t > sl) { if (noSt) throw "unexpected EOF"; break; } if (noBuf) cbuf(bt + l); buf.set(dat.subarray(s, t), bt); st.b = bt += l, st.p = pos = t * 8; continue; } else if (type == 1) lm = flrm, dm = fdrm, lbt = 9, dbt = 5; else if (type == 2) { var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; var tl = hLit + bits(dat, pos + 5, 31) + 1; pos += 14; var ldt = new u8(tl); var clt = new u8(19); for (var i = 0; i < hcLen; ++i) clt[clim[i]] = bits(dat, pos + i * 3, 7); pos += hcLen * 3; var clb = max(clt), clbmsk = (1 << clb) - 1; var clm = hMap(clt, clb, 1); for (var i = 0; i < tl;) { var r = clm[bits(dat, pos, clbmsk)]; pos += r & 15; var s = r >>> 4; if (s < 16) ldt[i++] = s; else { var c = 0, n = 0; if (s == 16) n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; else if (s == 17) n = 3 + bits(dat, pos, 7), pos += 3; else if (s == 18) n = 11 + bits(dat, pos, 127), pos += 7; while (n--) ldt[i++] = c; } } var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); lbt = max(lt); dbt = max(dt); lm = hMap(lt, lbt, 1); dm = hMap(dt, dbt, 1); } else throw "invalid block type"; if (pos > tbts) { if (noSt) throw "unexpected EOF"; break; } } if (noBuf) cbuf(bt + 131072); var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; var lpos = pos; for (;; lpos = pos) { var c = lm[bits16(dat, pos) & lms], sym = c >>> 4; pos += c & 15; if (pos > tbts) { if (noSt) throw "unexpected EOF"; break; } if (!c) throw "invalid length/literal"; if (sym < 256) buf[bt++] = sym; else if (sym == 256) { lpos = pos, lm = null; break; } else { var add = sym - 254; if (sym > 264) { var i = sym - 257, b = fleb[i]; add = bits(dat, pos, (1 << b) - 1) + fl[i]; pos += b; } var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4; if (!d) throw "invalid distance"; pos += d & 15; var dt = fd[dsym]; if (dsym > 3) { var b = fdeb[dsym]; dt += bits16(dat, pos) & (1 << b) - 1, pos += b; } if (pos > tbts) { if (noSt) throw "unexpected EOF"; break; } if (noBuf) cbuf(bt + 131072); var end = bt + add; for (; bt < end; bt += 4) { buf[bt] = buf[bt - dt]; buf[bt + 1] = buf[bt + 1 - dt]; buf[bt + 2] = buf[bt + 2 - dt]; buf[bt + 3] = buf[bt + 3 - dt]; } bt = end; } } st.l = lm, st.p = lpos, st.b = bt; if (lm) final = 1, st.m = lbt, st.d = dm, st.n = dbt; } while (!final); return bt == buf.length ? buf : slc(buf, 0, bt); }; var et = /*#__PURE__*/ new u8(0); var zlv = function(d) { if ((d[0] & 15) != 8 || d[0] >>> 4 > 7 || (d[0] << 8 | d[1]) % 31) throw "invalid zlib data"; if (d[1] & 32) throw "invalid zlib data: preset dictionaries not supported"; }; /** * Expands Zlib data * @param data The data to decompress * @param out Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length. * @returns The decompressed version of the data */ function unzlibSync(data, out) { return inflt((zlv(data), data.subarray(2, -4)), out); } var td = typeof TextDecoder != "undefined" && /*#__PURE__*/ new TextDecoder(); try { td.decode(et, { stream: true }); } catch (e) {} //#endregion //#region node_modules/three-stdlib/objects/MarchingCubes.js var MarchingCubes$1 = class extends Mesh { constructor(resolution, material, enableUvs = false, enableColors = false, maxPolyCount = 1e4) { const geometry = new BufferGeometry(); super(geometry, material); this.isMarchingCubes = true; const scope = this; const vlist = new Float32Array(36); const nlist = new Float32Array(36); const clist = new Float32Array(36); this.enableUvs = enableUvs; this.enableColors = enableColors; this.init = function(resolution2) { this.resolution = resolution2; this.isolation = 80; this.size = resolution2; this.size2 = this.size * this.size; this.size3 = this.size2 * this.size; this.halfsize = this.size / 2; this.delta = 2 / this.size; this.yd = this.size; this.zd = this.size2; this.field = new Float32Array(this.size3); this.normal_cache = new Float32Array(this.size3 * 3); this.palette = new Float32Array(this.size3 * 3); this.count = 0; const maxVertexCount = maxPolyCount * 3; this.positionArray = new Float32Array(maxVertexCount * 3); const positionAttribute = new BufferAttribute(this.positionArray, 3); positionAttribute.setUsage(DynamicDrawUsage); geometry.setAttribute("position", positionAttribute); this.normalArray = new Float32Array(maxVertexCount * 3); const normalAttribute = new BufferAttribute(this.normalArray, 3); normalAttribute.setUsage(DynamicDrawUsage); geometry.setAttribute("normal", normalAttribute); if (this.enableUvs) { this.uvArray = new Float32Array(maxVertexCount * 2); const uvAttribute = new BufferAttribute(this.uvArray, 2); uvAttribute.setUsage(DynamicDrawUsage); geometry.setAttribute("uv", uvAttribute); } if (this.enableColors) { this.colorArray = new Float32Array(maxVertexCount * 3); const colorAttribute = new BufferAttribute(this.colorArray, 3); colorAttribute.setUsage(DynamicDrawUsage); geometry.setAttribute("color", colorAttribute); } geometry.boundingSphere = new Sphere$1(new Vector3(), 1); }; function lerp(a, b, t) { return a + (b - a) * t; } function VIntX(q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2) { const mu = (isol - valp1) / (valp2 - valp1), nc = scope.normal_cache; vlist[offset + 0] = x + mu * scope.delta; vlist[offset + 1] = y; vlist[offset + 2] = z; nlist[offset + 0] = lerp(nc[q + 0], nc[q + 3], mu); nlist[offset + 1] = lerp(nc[q + 1], nc[q + 4], mu); nlist[offset + 2] = lerp(nc[q + 2], nc[q + 5], mu); clist[offset + 0] = lerp(scope.palette[c_offset1 * 3 + 0], scope.palette[c_offset2 * 3 + 0], mu); clist[offset + 1] = lerp(scope.palette[c_offset1 * 3 + 1], scope.palette[c_offset2 * 3 + 1], mu); clist[offset + 2] = lerp(scope.palette[c_offset1 * 3 + 2], scope.palette[c_offset2 * 3 + 2], mu); } function VIntY(q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2) { const mu = (isol - valp1) / (valp2 - valp1), nc = scope.normal_cache; vlist[offset + 0] = x; vlist[offset + 1] = y + mu * scope.delta; vlist[offset + 2] = z; const q2 = q + scope.yd * 3; nlist[offset + 0] = lerp(nc[q + 0], nc[q2 + 0], mu); nlist[offset + 1] = lerp(nc[q + 1], nc[q2 + 1], mu); nlist[offset + 2] = lerp(nc[q + 2], nc[q2 + 2], mu); clist[offset + 0] = lerp(scope.palette[c_offset1 * 3 + 0], scope.palette[c_offset2 * 3 + 0], mu); clist[offset + 1] = lerp(scope.palette[c_offset1 * 3 + 1], scope.palette[c_offset2 * 3 + 1], mu); clist[offset + 2] = lerp(scope.palette[c_offset1 * 3 + 2], scope.palette[c_offset2 * 3 + 2], mu); } function VIntZ(q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2) { const mu = (isol - valp1) / (valp2 - valp1), nc = scope.normal_cache; vlist[offset + 0] = x; vlist[offset + 1] = y; vlist[offset + 2] = z + mu * scope.delta; const q2 = q + scope.zd * 3; nlist[offset + 0] = lerp(nc[q + 0], nc[q2 + 0], mu); nlist[offset + 1] = lerp(nc[q + 1], nc[q2 + 1], mu); nlist[offset + 2] = lerp(nc[q + 2], nc[q2 + 2], mu); clist[offset + 0] = lerp(scope.palette[c_offset1 * 3 + 0], scope.palette[c_offset2 * 3 + 0], mu); clist[offset + 1] = lerp(scope.palette[c_offset1 * 3 + 1], scope.palette[c_offset2 * 3 + 1], mu); clist[offset + 2] = lerp(scope.palette[c_offset1 * 3 + 2], scope.palette[c_offset2 * 3 + 2], mu); } function compNorm(q) { const q3 = q * 3; if (scope.normal_cache[q3] === 0) { scope.normal_cache[q3 + 0] = scope.field[q - 1] - scope.field[q + 1]; scope.normal_cache[q3 + 1] = scope.field[q - scope.yd] - scope.field[q + scope.yd]; scope.normal_cache[q3 + 2] = scope.field[q - scope.zd] - scope.field[q + scope.zd]; } } function polygonize(fx, fy, fz, q, isol) { const q1 = q + 1, qy = q + scope.yd, qz = q + scope.zd, q1y = q1 + scope.yd, q1z = q1 + scope.zd, qyz = q + scope.yd + scope.zd, q1yz = q1 + scope.yd + scope.zd; let cubeindex = 0; const field0 = scope.field[q], field1 = scope.field[q1], field2 = scope.field[qy], field3 = scope.field[q1y], field4 = scope.field[qz], field5 = scope.field[q1z], field6 = scope.field[qyz], field7 = scope.field[q1yz]; if (field0 < isol) cubeindex |= 1; if (field1 < isol) cubeindex |= 2; if (field2 < isol) cubeindex |= 8; if (field3 < isol) cubeindex |= 4; if (field4 < isol) cubeindex |= 16; if (field5 < isol) cubeindex |= 32; if (field6 < isol) cubeindex |= 128; if (field7 < isol) cubeindex |= 64; const bits = edgeTable[cubeindex]; if (bits === 0) return 0; const d = scope.delta, fx2 = fx + d, fy2 = fy + d, fz2 = fz + d; if (bits & 1) { compNorm(q); compNorm(q1); VIntX(q * 3, 0, isol, fx, fy, fz, field0, field1, q, q1); } if (bits & 2) { compNorm(q1); compNorm(q1y); VIntY(q1 * 3, 3, isol, fx2, fy, fz, field1, field3, q1, q1y); } if (bits & 4) { compNorm(qy); compNorm(q1y); VIntX(qy * 3, 6, isol, fx, fy2, fz, field2, field3, qy, q1y); } if (bits & 8) { compNorm(q); compNorm(qy); VIntY(q * 3, 9, isol, fx, fy, fz, field0, field2, q, qy); } if (bits & 16) { compNorm(qz); compNorm(q1z); VIntX(qz * 3, 12, isol, fx, fy, fz2, field4, field5, qz, q1z); } if (bits & 32) { compNorm(q1z); compNorm(q1yz); VIntY(q1z * 3, 15, isol, fx2, fy, fz2, field5, field7, q1z, q1yz); } if (bits & 64) { compNorm(qyz); compNorm(q1yz); VIntX(qyz * 3, 18, isol, fx, fy2, fz2, field6, field7, qyz, q1yz); } if (bits & 128) { compNorm(qz); compNorm(qyz); VIntY(qz * 3, 21, isol, fx, fy, fz2, field4, field6, qz, qyz); } if (bits & 256) { compNorm(q); compNorm(qz); VIntZ(q * 3, 24, isol, fx, fy, fz, field0, field4, q, qz); } if (bits & 512) { compNorm(q1); compNorm(q1z); VIntZ(q1 * 3, 27, isol, fx2, fy, fz, field1, field5, q1, q1z); } if (bits & 1024) { compNorm(q1y); compNorm(q1yz); VIntZ(q1y * 3, 30, isol, fx2, fy2, fz, field3, field7, q1y, q1yz); } if (bits & 2048) { compNorm(qy); compNorm(qyz); VIntZ(qy * 3, 33, isol, fx, fy2, fz, field2, field6, qy, qyz); } cubeindex <<= 4; let o1, o2, o3, numtris = 0, i = 0; while (triTable[cubeindex + i] != -1) { o1 = cubeindex + i; o2 = o1 + 1; o3 = o1 + 2; posnormtriv(vlist, nlist, clist, 3 * triTable[o1], 3 * triTable[o2], 3 * triTable[o3]); i += 3; numtris++; } return numtris; } function posnormtriv(pos, norm, colors, o1, o2, o3) { const c = scope.count * 3; scope.positionArray[c + 0] = pos[o1]; scope.positionArray[c + 1] = pos[o1 + 1]; scope.positionArray[c + 2] = pos[o1 + 2]; scope.positionArray[c + 3] = pos[o2]; scope.positionArray[c + 4] = pos[o2 + 1]; scope.positionArray[c + 5] = pos[o2 + 2]; scope.positionArray[c + 6] = pos[o3]; scope.positionArray[c + 7] = pos[o3 + 1]; scope.positionArray[c + 8] = pos[o3 + 2]; if (scope.material.flatShading === true) { const nx = (norm[o1 + 0] + norm[o2 + 0] + norm[o3 + 0]) / 3; const ny = (norm[o1 + 1] + norm[o2 + 1] + norm[o3 + 1]) / 3; const nz = (norm[o1 + 2] + norm[o2 + 2] + norm[o3 + 2]) / 3; scope.normalArray[c + 0] = nx; scope.normalArray[c + 1] = ny; scope.normalArray[c + 2] = nz; scope.normalArray[c + 3] = nx; scope.normalArray[c + 4] = ny; scope.normalArray[c + 5] = nz; scope.normalArray[c + 6] = nx; scope.normalArray[c + 7] = ny; scope.normalArray[c + 8] = nz; } else { scope.normalArray[c + 0] = norm[o1 + 0]; scope.normalArray[c + 1] = norm[o1 + 1]; scope.normalArray[c + 2] = norm[o1 + 2]; scope.normalArray[c + 3] = norm[o2 + 0]; scope.normalArray[c + 4] = norm[o2 + 1]; scope.normalArray[c + 5] = norm[o2 + 2]; scope.normalArray[c + 6] = norm[o3 + 0]; scope.normalArray[c + 7] = norm[o3 + 1]; scope.normalArray[c + 8] = norm[o3 + 2]; } if (scope.enableUvs) { const d = scope.count * 2; scope.uvArray[d + 0] = pos[o1 + 0]; scope.uvArray[d + 1] = pos[o1 + 2]; scope.uvArray[d + 2] = pos[o2 + 0]; scope.uvArray[d + 3] = pos[o2 + 2]; scope.uvArray[d + 4] = pos[o3 + 0]; scope.uvArray[d + 5] = pos[o3 + 2]; } if (scope.enableColors) { scope.colorArray[c + 0] = colors[o1 + 0]; scope.colorArray[c + 1] = colors[o1 + 1]; scope.colorArray[c + 2] = colors[o1 + 2]; scope.colorArray[c + 3] = colors[o2 + 0]; scope.colorArray[c + 4] = colors[o2 + 1]; scope.colorArray[c + 5] = colors[o2 + 2]; scope.colorArray[c + 6] = colors[o3 + 0]; scope.colorArray[c + 7] = colors[o3 + 1]; scope.colorArray[c + 8] = colors[o3 + 2]; } scope.count += 3; } this.addBall = function(ballx, bally, ballz, strength, subtract, colors) { const sign = Math.sign(strength); strength = Math.abs(strength); const userDefineColor = !(colors === void 0 || colors === null); let ballColor = new Color(ballx, bally, ballz); if (userDefineColor) try { ballColor = colors instanceof Color ? colors : Array.isArray(colors) ? new Color(Math.min(Math.abs(colors[0]), 1), Math.min(Math.abs(colors[1]), 1), Math.min(Math.abs(colors[2]), 1)) : new Color(colors); } catch (err) { ballColor = new Color(ballx, bally, ballz); } const radius = this.size * Math.sqrt(strength / subtract), zs = ballz * this.size, ys = bally * this.size, xs = ballx * this.size; let min_z = Math.floor(zs - radius); if (min_z < 1) min_z = 1; let max_z = Math.floor(zs + radius); if (max_z > this.size - 1) max_z = this.size - 1; let min_y = Math.floor(ys - radius); if (min_y < 1) min_y = 1; let max_y = Math.floor(ys + radius); if (max_y > this.size - 1) max_y = this.size - 1; let min_x = Math.floor(xs - radius); if (min_x < 1) min_x = 1; let max_x = Math.floor(xs + radius); if (max_x > this.size - 1) max_x = this.size - 1; let x, y, z, y_offset, z_offset, fx, fy, fz, fz2, fy2, val; for (z = min_z; z < max_z; z++) { z_offset = this.size2 * z; fz = z / this.size - ballz; fz2 = fz * fz; for (y = min_y; y < max_y; y++) { y_offset = z_offset + this.size * y; fy = y / this.size - bally; fy2 = fy * fy; for (x = min_x; x < max_x; x++) { fx = x / this.size - ballx; val = strength / (1e-6 + fx * fx + fy2 + fz2) - subtract; if (val > 0) { this.field[y_offset + x] += val * sign; const ratio = Math.sqrt((x - xs) * (x - xs) + (y - ys) * (y - ys) + (z - zs) * (z - zs)) / radius; const contrib = 1 - ratio * ratio * ratio * (ratio * (ratio * 6 - 15) + 10); this.palette[(y_offset + x) * 3 + 0] += ballColor.r * contrib; this.palette[(y_offset + x) * 3 + 1] += ballColor.g * contrib; this.palette[(y_offset + x) * 3 + 2] += ballColor.b * contrib; } } } } }; this.addPlaneX = function(strength, subtract) { const size = this.size, yd = this.yd, zd = this.zd, field = this.field; let x, y, z, xx, val, xdiv, cxy, dist = size * Math.sqrt(strength / subtract); if (dist > size) dist = size; for (x = 0; x < dist; x++) { xdiv = x / size; xx = xdiv * xdiv; val = strength / (1e-4 + xx) - subtract; if (val > 0) for (y = 0; y < size; y++) { cxy = x + y * yd; for (z = 0; z < size; z++) field[zd * z + cxy] += val; } } }; this.addPlaneY = function(strength, subtract) { const size = this.size, yd = this.yd, zd = this.zd, field = this.field; let x, y, z, yy, val, ydiv, cy, cxy, dist = size * Math.sqrt(strength / subtract); if (dist > size) dist = size; for (y = 0; y < dist; y++) { ydiv = y / size; yy = ydiv * ydiv; val = strength / (1e-4 + yy) - subtract; if (val > 0) { cy = y * yd; for (x = 0; x < size; x++) { cxy = cy + x; for (z = 0; z < size; z++) field[zd * z + cxy] += val; } } } }; this.addPlaneZ = function(strength, subtract) { const size = this.size, yd = this.yd, zd = this.zd, field = this.field; let x, y, z, zz, val, zdiv, cz, cyz, dist = size * Math.sqrt(strength / subtract); if (dist > size) dist = size; for (z = 0; z < dist; z++) { zdiv = z / size; zz = zdiv * zdiv; val = strength / (1e-4 + zz) - subtract; if (val > 0) { cz = zd * z; for (y = 0; y < size; y++) { cyz = cz + y * yd; for (x = 0; x < size; x++) field[cyz + x] += val; } } } }; this.setCell = function(x, y, z, value) { const index = this.size2 * z + this.size * y + x; this.field[index] = value; }; this.getCell = function(x, y, z) { const index = this.size2 * z + this.size * y + x; return this.field[index]; }; this.blur = function(intensity = 1) { const field = this.field; const fieldCopy = field.slice(); const size = this.size; const size2 = this.size2; for (let x = 0; x < size; x++) for (let y = 0; y < size; y++) for (let z = 0; z < size; z++) { const index = size2 * z + size * y + x; let val = fieldCopy[index]; let count = 1; for (let x2 = -1; x2 <= 1; x2 += 2) { const x3 = x2 + x; if (x3 < 0 || x3 >= size) continue; for (let y2 = -1; y2 <= 1; y2 += 2) { const y3 = y2 + y; if (y3 < 0 || y3 >= size) continue; for (let z2 = -1; z2 <= 1; z2 += 2) { const z3 = z2 + z; if (z3 < 0 || z3 >= size) continue; const val2 = fieldCopy[size2 * z3 + size * y3 + x3]; count++; val += intensity * (val2 - val) / count; } } } field[index] = val; } }; this.reset = function() { for (let i = 0; i < this.size3; i++) { this.normal_cache[i * 3] = 0; this.field[i] = 0; this.palette[i * 3] = this.palette[i * 3 + 1] = this.palette[i * 3 + 2] = 0; } }; this.update = function() { this.count = 0; const smin2 = this.size - 2; for (let z = 1; z < smin2; z++) { const z_offset = this.size2 * z; const fz = (z - this.halfsize) / this.halfsize; for (let y = 1; y < smin2; y++) { const y_offset = z_offset + this.size * y; const fy = (y - this.halfsize) / this.halfsize; for (let x = 1; x < smin2; x++) polygonize((x - this.halfsize) / this.halfsize, fy, fz, y_offset + x, this.isolation); } } this.geometry.setDrawRange(0, this.count); geometry.getAttribute("position").needsUpdate = true; geometry.getAttribute("normal").needsUpdate = true; if (this.enableUvs) geometry.getAttribute("uv").needsUpdate = true; if (this.enableColors) geometry.getAttribute("color").needsUpdate = true; if (this.count / 3 > maxPolyCount) console.warn("THREE.MarchingCubes: Geometry buffers too small for rendering. Please create an instance with a higher poly count."); }; this.init(resolution); } }; var edgeTable = new Int32Array([ 0, 265, 515, 778, 1030, 1295, 1541, 1804, 2060, 2309, 2575, 2822, 3082, 3331, 3593, 3840, 400, 153, 915, 666, 1430, 1183, 1941, 1692, 2460, 2197, 2975, 2710, 3482, 3219, 3993, 3728, 560, 825, 51, 314, 1590, 1855, 1077, 1340, 2620, 2869, 2111, 2358, 3642, 3891, 3129, 3376, 928, 681, 419, 170, 1958, 1711, 1445, 1196, 2988, 2725, 2479, 2214, 4010, 3747, 3497, 3232, 1120, 1385, 1635, 1898, 102, 367, 613, 876, 3180, 3429, 3695, 3942, 2154, 2403, 2665, 2912, 1520, 1273, 2035, 1786, 502, 255, 1013, 764, 3580, 3317, 4095, 3830, 2554, 2291, 3065, 2800, 1616, 1881, 1107, 1370, 598, 863, 85, 348, 3676, 3925, 3167, 3414, 2650, 2899, 2137, 2384, 1984, 1737, 1475, 1226, 966, 719, 453, 204, 4044, 3781, 3535, 3270, 3018, 2755, 2505, 2240, 2240, 2505, 2755, 3018, 3270, 3535, 3781, 4044, 204, 453, 719, 966, 1226, 1475, 1737, 1984, 2384, 2137, 2899, 2650, 3414, 3167, 3925, 3676, 348, 85, 863, 598, 1370, 1107, 1881, 1616, 2800, 3065, 2291, 2554, 3830, 4095, 3317, 3580, 764, 1013, 255, 502, 1786, 2035, 1273, 1520, 2912, 2665, 2403, 2154, 3942, 3695, 3429, 3180, 876, 613, 367, 102, 1898, 1635, 1385, 1120, 3232, 3497, 3747, 4010, 2214, 2479, 2725, 2988, 1196, 1445, 1711, 1958, 170, 419, 681, 928, 3376, 3129, 3891, 3642, 2358, 2111, 2869, 2620, 1340, 1077, 1855, 1590, 314, 51, 825, 560, 3728, 3993, 3219, 3482, 2710, 2975, 2197, 2460, 1692, 1941, 1183, 1430, 666, 915, 153, 400, 3840, 3593, 3331, 3082, 2822, 2575, 2309, 2060, 1804, 1541, 1295, 1030, 778, 515, 265, 0 ]); var triTable = new Int32Array([ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1, 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1, 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1, 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1, 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1, 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1, 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1, 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1, 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1, 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1, 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1, 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1, 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1, 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1, 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1, 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1, 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1, 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1, 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1, 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1, 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1, 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1, 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1, 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1, 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1, 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1, 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1, 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1, 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1, 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1, 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1, 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1, 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1, 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1, 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1, 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1, 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1, 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1, 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1, 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1, 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1, 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1, 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1, 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1, 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1, 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1, 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1, 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1, 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1, 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1, 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1, 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1, 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1, 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1, 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1, 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1, 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1, 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1, 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1, 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1, 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1, 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1, 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1, 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1, 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1, 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1, 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1, 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1, 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1, 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1, 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1, 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1, 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1, 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1, 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1, 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1, 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1, 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1, 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1, 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1, 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1, 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1, 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1, 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1, 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1, 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1, 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1, 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1, 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1, 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1, 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1, 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1, 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1, 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1, 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1, 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1, 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1, 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1, 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1, 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1, 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1, 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1, 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1, 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1, 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1, 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1, 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1, 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1, 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1, 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1, 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1, 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1, 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1, 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1, 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1, 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1, 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1, 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1, 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1, 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1, 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1, 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1, 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1, 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1, 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1, 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1, 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1, 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1, 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1, 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1, 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1, 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1, 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1, 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1, 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1, 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1, 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1, 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1, 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ]); //#endregion //#region node_modules/three-stdlib/math/SimplexNoise.js var __defProp$18 = Object.defineProperty; var __defNormalProp$18 = (obj, key, value) => key in obj ? __defProp$18(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$18 = (obj, key, value) => { __defNormalProp$18(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var SimplexNoise = class { /** * You can pass in a random number generator object if you like. * It is assumed to have a random() method. */ constructor(r = Math) { __publicField$18(this, "grad3", [ [ 1, 1, 0 ], [ -1, 1, 0 ], [ 1, -1, 0 ], [ -1, -1, 0 ], [ 1, 0, 1 ], [ -1, 0, 1 ], [ 1, 0, -1 ], [ -1, 0, -1 ], [ 0, 1, 1 ], [ 0, -1, 1 ], [ 0, 1, -1 ], [ 0, -1, -1 ] ]); __publicField$18(this, "grad4", [ [ 0, 1, 1, 1 ], [ 0, 1, 1, -1 ], [ 0, 1, -1, 1 ], [ 0, 1, -1, -1 ], [ 0, -1, 1, 1 ], [ 0, -1, 1, -1 ], [ 0, -1, -1, 1 ], [ 0, -1, -1, -1 ], [ 1, 0, 1, 1 ], [ 1, 0, 1, -1 ], [ 1, 0, -1, 1 ], [ 1, 0, -1, -1 ], [ -1, 0, 1, 1 ], [ -1, 0, 1, -1 ], [ -1, 0, -1, 1 ], [ -1, 0, -1, -1 ], [ 1, 1, 0, 1 ], [ 1, 1, 0, -1 ], [ 1, -1, 0, 1 ], [ 1, -1, 0, -1 ], [ -1, 1, 0, 1 ], [ -1, 1, 0, -1 ], [ -1, -1, 0, 1 ], [ -1, -1, 0, -1 ], [ 1, 1, 1, 0 ], [ 1, 1, -1, 0 ], [ 1, -1, 1, 0 ], [ 1, -1, -1, 0 ], [ -1, 1, 1, 0 ], [ -1, 1, -1, 0 ], [ -1, -1, 1, 0 ], [ -1, -1, -1, 0 ] ]); __publicField$18(this, "p", []); __publicField$18(this, "perm", []); __publicField$18(this, "simplex", [ [ 0, 1, 2, 3 ], [ 0, 1, 3, 2 ], [ 0, 0, 0, 0 ], [ 0, 2, 3, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 1, 2, 3, 0 ], [ 0, 2, 1, 3 ], [ 0, 0, 0, 0 ], [ 0, 3, 1, 2 ], [ 0, 3, 2, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 1, 3, 2, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 1, 2, 0, 3 ], [ 0, 0, 0, 0 ], [ 1, 3, 0, 2 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 2, 3, 0, 1 ], [ 2, 3, 1, 0 ], [ 1, 0, 2, 3 ], [ 1, 0, 3, 2 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 2, 0, 3, 1 ], [ 0, 0, 0, 0 ], [ 2, 1, 3, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 2, 0, 1, 3 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 3, 0, 1, 2 ], [ 3, 0, 2, 1 ], [ 0, 0, 0, 0 ], [ 3, 1, 2, 0 ], [ 2, 1, 0, 3 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 3, 1, 0, 2 ], [ 0, 0, 0, 0 ], [ 3, 2, 0, 1 ], [ 3, 2, 1, 0 ] ]); __publicField$18(this, "dot", (g, x, y) => { return g[0] * x + g[1] * y; }); __publicField$18(this, "dot3", (g, x, y, z) => { return g[0] * x + g[1] * y + g[2] * z; }); __publicField$18(this, "dot4", (g, x, y, z, w) => { return g[0] * x + g[1] * y + g[2] * z + g[3] * w; }); __publicField$18(this, "noise", (xin, yin) => { let n0; let n1; let n2; const F2 = .5 * (Math.sqrt(3) - 1); const s = (xin + yin) * F2; const i = Math.floor(xin + s); const j = Math.floor(yin + s); const G2 = (3 - Math.sqrt(3)) / 6; const t = (i + j) * G2; const X0 = i - t; const Y0 = j - t; const x0 = xin - X0; const y0 = yin - Y0; let i1 = 0; let j1 = 1; if (x0 > y0) { i1 = 1; j1 = 0; } const x1 = x0 - i1 + G2; const y1 = y0 - j1 + G2; const x2 = x0 - 1 + 2 * G2; const y2 = y0 - 1 + 2 * G2; const ii = i & 255; const jj = j & 255; const gi0 = this.perm[ii + this.perm[jj]] % 12; const gi1 = this.perm[ii + i1 + this.perm[jj + j1]] % 12; const gi2 = this.perm[ii + 1 + this.perm[jj + 1]] % 12; let t0 = .5 - x0 * x0 - y0 * y0; if (t0 < 0) n0 = 0; else { t0 *= t0; n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0); } let t1 = .5 - x1 * x1 - y1 * y1; if (t1 < 0) n1 = 0; else { t1 *= t1; n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1); } let t2 = .5 - x2 * x2 - y2 * y2; if (t2 < 0) n2 = 0; else { t2 *= t2; n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2); } return 70 * (n0 + n1 + n2); }); __publicField$18(this, "noise3d", (xin, yin, zin) => { let n0; let n1; let n2; let n3; const s = (xin + yin + zin) * (1 / 3); const i = Math.floor(xin + s); const j = Math.floor(yin + s); const k = Math.floor(zin + s); const G3 = 1 / 6; const t = (i + j + k) * G3; const X0 = i - t; const Y0 = j - t; const Z0 = k - t; const x0 = xin - X0; const y0 = yin - Y0; const z0 = zin - Z0; let i1; let j1; let k1; let i2; let j2; let k2; if (x0 >= y0) if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } else if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } const x1 = x0 - i1 + G3; const y1 = y0 - j1 + G3; const z1 = z0 - k1 + G3; const x2 = x0 - i2 + 2 * G3; const y2 = y0 - j2 + 2 * G3; const z2 = z0 - k2 + 2 * G3; const x3 = x0 - 1 + 3 * G3; const y3 = y0 - 1 + 3 * G3; const z3 = z0 - 1 + 3 * G3; const ii = i & 255; const jj = j & 255; const kk = k & 255; const gi0 = this.perm[ii + this.perm[jj + this.perm[kk]]] % 12; const gi1 = this.perm[ii + i1 + this.perm[jj + j1 + this.perm[kk + k1]]] % 12; const gi2 = this.perm[ii + i2 + this.perm[jj + j2 + this.perm[kk + k2]]] % 12; const gi3 = this.perm[ii + 1 + this.perm[jj + 1 + this.perm[kk + 1]]] % 12; let t0 = .6 - x0 * x0 - y0 * y0 - z0 * z0; if (t0 < 0) n0 = 0; else { t0 *= t0; n0 = t0 * t0 * this.dot3(this.grad3[gi0], x0, y0, z0); } let t1 = .6 - x1 * x1 - y1 * y1 - z1 * z1; if (t1 < 0) n1 = 0; else { t1 *= t1; n1 = t1 * t1 * this.dot3(this.grad3[gi1], x1, y1, z1); } let t2 = .6 - x2 * x2 - y2 * y2 - z2 * z2; if (t2 < 0) n2 = 0; else { t2 *= t2; n2 = t2 * t2 * this.dot3(this.grad3[gi2], x2, y2, z2); } let t3 = .6 - x3 * x3 - y3 * y3 - z3 * z3; if (t3 < 0) n3 = 0; else { t3 *= t3; n3 = t3 * t3 * this.dot3(this.grad3[gi3], x3, y3, z3); } return 32 * (n0 + n1 + n2 + n3); }); __publicField$18(this, "noise4d", (x, y, z, w) => { const grad4 = this.grad4; const simplex = this.simplex; const perm = this.perm; const F4 = (Math.sqrt(5) - 1) / 4; const G4 = (5 - Math.sqrt(5)) / 20; let n0; let n1; let n2; let n3; let n4; const s = (x + y + z + w) * F4; const i = Math.floor(x + s); const j = Math.floor(y + s); const k = Math.floor(z + s); const l = Math.floor(w + s); const t = (i + j + k + l) * G4; const X0 = i - t; const Y0 = j - t; const Z0 = k - t; const W0 = l - t; const x0 = x - X0; const y0 = y - Y0; const z0 = z - Z0; const w0 = w - W0; const c1 = x0 > y0 ? 32 : 0; const c2 = x0 > z0 ? 16 : 0; const c3 = y0 > z0 ? 8 : 0; const c4 = x0 > w0 ? 4 : 0; const c5 = y0 > w0 ? 2 : 0; const c6 = z0 > w0 ? 1 : 0; const c = c1 + c2 + c3 + c4 + c5 + c6; let i1; let j1; let k1; let l1; let i2; let j2; let k2; let l2; let i3; let j3; let k3; let l3; i1 = simplex[c][0] >= 3 ? 1 : 0; j1 = simplex[c][1] >= 3 ? 1 : 0; k1 = simplex[c][2] >= 3 ? 1 : 0; l1 = simplex[c][3] >= 3 ? 1 : 0; i2 = simplex[c][0] >= 2 ? 1 : 0; j2 = simplex[c][1] >= 2 ? 1 : 0; k2 = simplex[c][2] >= 2 ? 1 : 0; l2 = simplex[c][3] >= 2 ? 1 : 0; i3 = simplex[c][0] >= 1 ? 1 : 0; j3 = simplex[c][1] >= 1 ? 1 : 0; k3 = simplex[c][2] >= 1 ? 1 : 0; l3 = simplex[c][3] >= 1 ? 1 : 0; const x1 = x0 - i1 + G4; const y1 = y0 - j1 + G4; const z1 = z0 - k1 + G4; const w1 = w0 - l1 + G4; const x2 = x0 - i2 + 2 * G4; const y2 = y0 - j2 + 2 * G4; const z2 = z0 - k2 + 2 * G4; const w2 = w0 - l2 + 2 * G4; const x3 = x0 - i3 + 3 * G4; const y3 = y0 - j3 + 3 * G4; const z3 = z0 - k3 + 3 * G4; const w3 = w0 - l3 + 3 * G4; const x4 = x0 - 1 + 4 * G4; const y4 = y0 - 1 + 4 * G4; const z4 = z0 - 1 + 4 * G4; const w4 = w0 - 1 + 4 * G4; const ii = i & 255; const jj = j & 255; const kk = k & 255; const ll = l & 255; const gi0 = perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32; const gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32; const gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32; const gi3 = perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32; const gi4 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32; let t0 = .6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; if (t0 < 0) n0 = 0; else { t0 *= t0; n0 = t0 * t0 * this.dot4(grad4[gi0], x0, y0, z0, w0); } let t1 = .6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; if (t1 < 0) n1 = 0; else { t1 *= t1; n1 = t1 * t1 * this.dot4(grad4[gi1], x1, y1, z1, w1); } let t2 = .6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; if (t2 < 0) n2 = 0; else { t2 *= t2; n2 = t2 * t2 * this.dot4(grad4[gi2], x2, y2, z2, w2); } let t3 = .6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; if (t3 < 0) n3 = 0; else { t3 *= t3; n3 = t3 * t3 * this.dot4(grad4[gi3], x3, y3, z3, w3); } let t4 = .6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; if (t4 < 0) n4 = 0; else { t4 *= t4; n4 = t4 * t4 * this.dot4(grad4[gi4], x4, y4, z4, w4); } return 27 * (n0 + n1 + n2 + n3 + n4); }); for (let i = 0; i < 256; i++) this.p[i] = Math.floor(r.random() * 256); for (let i = 0; i < 512; i++) this.perm[i] = this.p[i & 255]; } }; //#endregion //#region node_modules/three-stdlib/objects/Sky.js var __defProp$17 = Object.defineProperty; var __defNormalProp$17 = (obj, key, value) => key in obj ? __defProp$17(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$17 = (obj, key, value) => { __defNormalProp$17(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var Sky$1 = /* @__PURE__ */ (() => { const SkyShader = { uniforms: { turbidity: { value: 2 }, rayleigh: { value: 1 }, mieCoefficient: { value: .005 }, mieDirectionalG: { value: .8 }, sunPosition: { value: new Vector3() }, up: { value: new Vector3(0, 1, 0) } }, vertexShader: ` uniform vec3 sunPosition; uniform float rayleigh; uniform float turbidity; uniform float mieCoefficient; uniform vec3 up; varying vec3 vWorldPosition; varying vec3 vSunDirection; varying float vSunfade; varying vec3 vBetaR; varying vec3 vBetaM; varying float vSunE; // constants for atmospheric scattering const float e = 2.71828182845904523536028747135266249775724709369995957; const float pi = 3.141592653589793238462643383279502884197169; // wavelength of used primaries, according to preetham const vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 ); // this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function: // (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn)) const vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 ); // mie stuff // K coefficient for the primaries const float v = 4.0; const vec3 K = vec3( 0.686, 0.678, 0.666 ); // MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K const vec3 MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 ); // earth shadow hack // cutoffAngle = pi / 1.95; const float cutoffAngle = 1.6110731556870734; const float steepness = 1.5; const float EE = 1000.0; float sunIntensity( float zenithAngleCos ) { zenithAngleCos = clamp( zenithAngleCos, -1.0, 1.0 ); return EE * max( 0.0, 1.0 - pow( e, -( ( cutoffAngle - acos( zenithAngleCos ) ) / steepness ) ) ); } vec3 totalMie( float T ) { float c = ( 0.2 * T ) * 10E-18; return 0.434 * c * MieConst; } void main() { vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); vWorldPosition = worldPosition.xyz; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); gl_Position.z = gl_Position.w; // set z to camera.far vSunDirection = normalize( sunPosition ); vSunE = sunIntensity( dot( vSunDirection, up ) ); vSunfade = 1.0 - clamp( 1.0 - exp( ( sunPosition.y / 450000.0 ) ), 0.0, 1.0 ); float rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) ); // extinction (absorbtion + out scattering) // rayleigh coefficients vBetaR = totalRayleigh * rayleighCoefficient; // mie coefficients vBetaM = totalMie( turbidity ) * mieCoefficient; } `, fragmentShader: ` varying vec3 vWorldPosition; varying vec3 vSunDirection; varying float vSunfade; varying vec3 vBetaR; varying vec3 vBetaM; varying float vSunE; uniform float mieDirectionalG; uniform vec3 up; const vec3 cameraPos = vec3( 0.0, 0.0, 0.0 ); // constants for atmospheric scattering const float pi = 3.141592653589793238462643383279502884197169; const float n = 1.0003; // refractive index of air const float N = 2.545E25; // number of molecules per unit volume for air at 288.15K and 1013mb (sea level -45 celsius) // optical length at zenith for molecules const float rayleighZenithLength = 8.4E3; const float mieZenithLength = 1.25E3; // 66 arc seconds -> degrees, and the cosine of that const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324; // 3.0 / ( 16.0 * pi ) const float THREE_OVER_SIXTEENPI = 0.05968310365946075; // 1.0 / ( 4.0 * pi ) const float ONE_OVER_FOURPI = 0.07957747154594767; float rayleighPhase( float cosTheta ) { return THREE_OVER_SIXTEENPI * ( 1.0 + pow( cosTheta, 2.0 ) ); } float hgPhase( float cosTheta, float g ) { float g2 = pow( g, 2.0 ); float inverse = 1.0 / pow( 1.0 - 2.0 * g * cosTheta + g2, 1.5 ); return ONE_OVER_FOURPI * ( ( 1.0 - g2 ) * inverse ); } void main() { vec3 direction = normalize( vWorldPosition - cameraPos ); // optical length // cutoff angle at 90 to avoid singularity in next formula. float zenithAngle = acos( max( 0.0, dot( up, direction ) ) ); float inverse = 1.0 / ( cos( zenithAngle ) + 0.15 * pow( 93.885 - ( ( zenithAngle * 180.0 ) / pi ), -1.253 ) ); float sR = rayleighZenithLength * inverse; float sM = mieZenithLength * inverse; // combined extinction factor vec3 Fex = exp( -( vBetaR * sR + vBetaM * sM ) ); // in scattering float cosTheta = dot( direction, vSunDirection ); float rPhase = rayleighPhase( cosTheta * 0.5 + 0.5 ); vec3 betaRTheta = vBetaR * rPhase; float mPhase = hgPhase( cosTheta, mieDirectionalG ); vec3 betaMTheta = vBetaM * mPhase; vec3 Lin = pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * ( 1.0 - Fex ), vec3( 1.5 ) ); Lin *= mix( vec3( 1.0 ), pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * Fex, vec3( 1.0 / 2.0 ) ), clamp( pow( 1.0 - dot( up, vSunDirection ), 5.0 ), 0.0, 1.0 ) ); // nightsky float theta = acos( direction.y ); // elevation --> y-axis, [-pi/2, pi/2] float phi = atan( direction.z, direction.x ); // azimuth --> x-axis [-pi/2, pi/2] vec2 uv = vec2( phi, theta ) / vec2( 2.0 * pi, pi ) + vec2( 0.5, 0.0 ); vec3 L0 = vec3( 0.1 ) * Fex; // composition + solar disc float sundisk = smoothstep( sunAngularDiameterCos, sunAngularDiameterCos + 0.00002, cosTheta ); L0 += ( vSunE * 19000.0 * Fex ) * sundisk; vec3 texColor = ( Lin + L0 ) * 0.04 + vec3( 0.0, 0.0003, 0.00075 ); vec3 retColor = pow( texColor, vec3( 1.0 / ( 1.2 + ( 1.2 * vSunfade ) ) ) ); gl_FragColor = vec4( retColor, 1.0 ); #include #include <${version$2 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } ` }; const material = new ShaderMaterial({ name: "SkyShader", fragmentShader: SkyShader.fragmentShader, vertexShader: SkyShader.vertexShader, uniforms: UniformsUtils.clone(SkyShader.uniforms), side: 1, depthWrite: false }); class Sky2 extends Mesh { constructor() { super(new BoxGeometry(1, 1, 1), material); } } __publicField$17(Sky2, "SkyShader", SkyShader); __publicField$17(Sky2, "material", material); return Sky2; })(); //#endregion //#region node_modules/three-stdlib/objects/GroundProjectedEnv.js var isCubeTexture$1 = (def) => def && def.isCubeTexture; var GroundProjectedEnv = class extends Mesh { constructor(texture, options) { var _a, _b; const isCubeMap = isCubeTexture$1(texture); const cubeSize = ((_b = isCubeMap ? (_a = texture.image[0]) == null ? void 0 : _a.width : texture.image.width) != null ? _b : 1024) / 4; const _lodMax = Math.floor(Math.log2(cubeSize)); const _cubeSize = Math.pow(2, _lodMax); const width = 3 * Math.max(_cubeSize, 112); const height = 4 * _cubeSize; const defines = [ isCubeMap ? "#define ENVMAP_TYPE_CUBE" : "", `#define CUBEUV_TEXEL_WIDTH ${1 / width}`, `#define CUBEUV_TEXEL_HEIGHT ${1 / height}`, `#define CUBEUV_MAX_MIP ${_lodMax}.0` ]; const vertexShader = ` varying vec3 vWorldPosition; void main() { vec4 worldPosition = ( modelMatrix * vec4( position, 1.0 ) ); vWorldPosition = worldPosition.xyz; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `; const fragmentShader = defines.join("\n") + ` #define ENVMAP_TYPE_CUBE_UV varying vec3 vWorldPosition; uniform float radius; uniform float height; uniform float angle; #ifdef ENVMAP_TYPE_CUBE uniform samplerCube map; #else uniform sampler2D map; #endif // From: https://www.shadertoy.com/view/4tsBD7 float diskIntersectWithBackFaceCulling( vec3 ro, vec3 rd, vec3 c, vec3 n, float r ) { float d = dot ( rd, n ); if( d > 0.0 ) { return 1e6; } vec3 o = ro - c; float t = - dot( n, o ) / d; vec3 q = o + rd * t; return ( dot( q, q ) < r * r ) ? t : 1e6; } // From: https://www.iquilezles.org/www/articles/intersectors/intersectors.htm float sphereIntersect( vec3 ro, vec3 rd, vec3 ce, float ra ) { vec3 oc = ro - ce; float b = dot( oc, rd ); float c = dot( oc, oc ) - ra * ra; float h = b * b - c; if( h < 0.0 ) { return -1.0; } h = sqrt( h ); return - b + h; } vec3 project() { vec3 p = normalize( vWorldPosition ); vec3 camPos = cameraPosition; camPos.y -= height; float intersection = sphereIntersect( camPos, p, vec3( 0.0 ), radius ); if( intersection > 0.0 ) { vec3 h = vec3( 0.0, - height, 0.0 ); float intersection2 = diskIntersectWithBackFaceCulling( camPos, p, h, vec3( 0.0, 1.0, 0.0 ), radius ); p = ( camPos + min( intersection, intersection2 ) * p ) / radius; } else { p = vec3( 0.0, 1.0, 0.0 ); } return p; } #include #include void main() { vec3 projectedWorldPosition = project(); #ifdef ENVMAP_TYPE_CUBE vec3 outcolor = textureCube( map, projectedWorldPosition ).rgb; #else vec3 direction = normalize( projectedWorldPosition ); vec2 uv = equirectUv( direction ); vec3 outcolor = texture2D( map, uv ).rgb; #endif gl_FragColor = vec4( outcolor, 1.0 ); #include #include <${version$2 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } `; const uniforms = { map: { value: texture }, height: { value: (options == null ? void 0 : options.height) || 15 }, radius: { value: (options == null ? void 0 : options.radius) || 100 } }; const geometry = new IcosahedronGeometry(1, 16); const material = new ShaderMaterial({ uniforms, fragmentShader, vertexShader, side: 2 }); super(geometry, material); } set radius(radius) { this.material.uniforms.radius.value = radius; } get radius() { return this.material.uniforms.radius.value; } set height(height) { this.material.uniforms.height.value = height; } get height() { return this.material.uniforms.height.value; } }; //#endregion //#region node_modules/three-stdlib/utils/SkeletonUtils.js function retarget(target, source, options = {}) { const pos = new Vector3(), quat = new Quaternion(), scale = new Vector3(), bindBoneMatrix = new Matrix4(), relativeMatrix = new Matrix4(), globalMatrix = new Matrix4(); options.preserveMatrix = options.preserveMatrix !== void 0 ? options.preserveMatrix : true; options.preservePosition = options.preservePosition !== void 0 ? options.preservePosition : true; options.preserveHipPosition = options.preserveHipPosition !== void 0 ? options.preserveHipPosition : false; options.useTargetMatrix = options.useTargetMatrix !== void 0 ? options.useTargetMatrix : false; options.hip = options.hip !== void 0 ? options.hip : "hip"; options.names = options.names || {}; const sourceBones = source.isObject3D ? source.skeleton.bones : getBones(source), bones = target.isObject3D ? target.skeleton.bones : getBones(target); let bindBones, bone, name, boneTo, bonesPosition; if (target.isObject3D) target.skeleton.pose(); else { options.useTargetMatrix = true; options.preserveMatrix = false; } if (options.preservePosition) { bonesPosition = []; for (let i = 0; i < bones.length; i++) bonesPosition.push(bones[i].position.clone()); } if (options.preserveMatrix) { target.updateMatrixWorld(); target.matrixWorld.identity(); for (let i = 0; i < target.children.length; ++i) target.children[i].updateMatrixWorld(true); } if (options.offsets) { bindBones = []; for (let i = 0; i < bones.length; ++i) { bone = bones[i]; name = options.names[bone.name] || bone.name; if (options.offsets[name]) { bone.matrix.multiply(options.offsets[name]); bone.matrix.decompose(bone.position, bone.quaternion, bone.scale); bone.updateMatrixWorld(); } bindBones.push(bone.matrixWorld.clone()); } } for (let i = 0; i < bones.length; ++i) { bone = bones[i]; name = options.names[bone.name] || bone.name; boneTo = getBoneByName(name, sourceBones); globalMatrix.copy(bone.matrixWorld); if (boneTo) { boneTo.updateMatrixWorld(); if (options.useTargetMatrix) relativeMatrix.copy(boneTo.matrixWorld); else { relativeMatrix.copy(target.matrixWorld).invert(); relativeMatrix.multiply(boneTo.matrixWorld); } scale.setFromMatrixScale(relativeMatrix); relativeMatrix.scale(scale.set(1 / scale.x, 1 / scale.y, 1 / scale.z)); globalMatrix.makeRotationFromQuaternion(quat.setFromRotationMatrix(relativeMatrix)); if (target.isObject3D) { const boneIndex = bones.indexOf(bone), wBindMatrix = bindBones ? bindBones[boneIndex] : bindBoneMatrix.copy(target.skeleton.boneInverses[boneIndex]).invert(); globalMatrix.multiply(wBindMatrix); } globalMatrix.copyPosition(relativeMatrix); } if (bone.parent && bone.parent.isBone) { bone.matrix.copy(bone.parent.matrixWorld).invert(); bone.matrix.multiply(globalMatrix); } else bone.matrix.copy(globalMatrix); if (options.preserveHipPosition && name === options.hip) bone.matrix.setPosition(pos.set(0, bone.position.y, 0)); bone.matrix.decompose(bone.position, bone.quaternion, bone.scale); bone.updateMatrixWorld(); } if (options.preservePosition) for (let i = 0; i < bones.length; ++i) { bone = bones[i]; name = options.names[bone.name] || bone.name; if (name !== options.hip) bone.position.copy(bonesPosition[i]); } if (options.preserveMatrix) target.updateMatrixWorld(true); } function retargetClip(target, source, clip, options = {}) { options.useFirstFramePosition = options.useFirstFramePosition !== void 0 ? options.useFirstFramePosition : false; options.fps = options.fps !== void 0 ? options.fps : 30; options.names = options.names || []; if (!source.isObject3D) source = getHelperFromSkeleton(source); const numFrames = Math.round(clip.duration * (options.fps / 1e3) * 1e3), delta = 1 / options.fps, convertedTracks = [], mixer = new AnimationMixer(source), bones = getBones(target.skeleton), boneDatas = []; let positionOffset, bone, boneTo, boneData, name; mixer.clipAction(clip).play(); mixer.update(0); source.updateMatrixWorld(); for (let i = 0; i < numFrames; ++i) { const time = i * delta; retarget(target, source, options); for (let j = 0; j < bones.length; ++j) { name = options.names[bones[j].name] || bones[j].name; boneTo = getBoneByName(name, source.skeleton); if (boneTo) { bone = bones[j]; boneData = boneDatas[j] = boneDatas[j] || { bone }; if (options.hip === name) { if (!boneData.pos) boneData.pos = { times: new Float32Array(numFrames), values: new Float32Array(numFrames * 3) }; if (options.useFirstFramePosition) { if (i === 0) positionOffset = bone.position.clone(); bone.position.sub(positionOffset); } boneData.pos.times[i] = time; bone.position.toArray(boneData.pos.values, i * 3); } if (!boneData.quat) boneData.quat = { times: new Float32Array(numFrames), values: new Float32Array(numFrames * 4) }; boneData.quat.times[i] = time; bone.quaternion.toArray(boneData.quat.values, i * 4); } } mixer.update(delta); source.updateMatrixWorld(); } for (let i = 0; i < boneDatas.length; ++i) { boneData = boneDatas[i]; if (boneData) { if (boneData.pos) convertedTracks.push(new VectorKeyframeTrack(".bones[" + boneData.bone.name + "].position", boneData.pos.times, boneData.pos.values)); convertedTracks.push(new QuaternionKeyframeTrack(".bones[" + boneData.bone.name + "].quaternion", boneData.quat.times, boneData.quat.values)); } } mixer.uncacheAction(clip); return new AnimationClip(clip.name, -1, convertedTracks); } function clone(source) { const sourceLookup = /* @__PURE__ */ new Map(); const cloneLookup = /* @__PURE__ */ new Map(); const clone2 = source.clone(); parallelTraverse(source, clone2, function(sourceNode, clonedNode) { sourceLookup.set(clonedNode, sourceNode); cloneLookup.set(sourceNode, clonedNode); }); clone2.traverse(function(node) { if (!node.isSkinnedMesh) return; const clonedMesh = node; const sourceMesh = sourceLookup.get(node); const sourceBones = sourceMesh.skeleton.bones; clonedMesh.skeleton = sourceMesh.skeleton.clone(); clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix); clonedMesh.skeleton.bones = sourceBones.map(function(bone) { return cloneLookup.get(bone); }); clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix); }); return clone2; } function getBoneByName(name, skeleton) { for (let i = 0, bones = getBones(skeleton); i < bones.length; i++) if (name === bones[i].name) return bones[i]; } function getBones(skeleton) { return Array.isArray(skeleton) ? skeleton : skeleton.bones; } function getHelperFromSkeleton(skeleton) { const source = new SkeletonHelper(skeleton.bones[0]); source.skeleton = skeleton; return source; } function parallelTraverse(a, b, callback) { callback(a, b); for (let i = 0; i < a.children.length; i++) parallelTraverse(a.children[i], b.children[i], callback); } var SkeletonUtils = { retarget, retargetClip, clone }; //#endregion //#region node_modules/three-stdlib/math/MeshSurfaceSampler.js var _face = /* @__PURE__ */ new Triangle(); var _color = /* @__PURE__ */ new Vector3(); var MeshSurfaceSampler = class { constructor(mesh) { let geometry = mesh.geometry; if (geometry.index) { console.warn("THREE.MeshSurfaceSampler: Converting geometry to non-indexed BufferGeometry."); geometry = geometry.toNonIndexed(); } this.geometry = geometry; this.randomFunction = Math.random; this.positionAttribute = this.geometry.getAttribute("position"); this.colorAttribute = this.geometry.getAttribute("color"); this.weightAttribute = null; this.distribution = null; } setWeightAttribute(name) { this.weightAttribute = name ? this.geometry.getAttribute(name) : null; return this; } build() { const positionAttribute = this.positionAttribute; const weightAttribute = this.weightAttribute; const faceWeights = new Float32Array(positionAttribute.count / 3); for (let i = 0; i < positionAttribute.count; i += 3) { let faceWeight = 1; if (weightAttribute) faceWeight = weightAttribute.getX(i) + weightAttribute.getX(i + 1) + weightAttribute.getX(i + 2); _face.a.fromBufferAttribute(positionAttribute, i); _face.b.fromBufferAttribute(positionAttribute, i + 1); _face.c.fromBufferAttribute(positionAttribute, i + 2); faceWeight *= _face.getArea(); faceWeights[i / 3] = faceWeight; } this.distribution = new Float32Array(positionAttribute.count / 3); let cumulativeTotal = 0; for (let i = 0; i < faceWeights.length; i++) { cumulativeTotal += faceWeights[i]; this.distribution[i] = cumulativeTotal; } return this; } setRandomGenerator(randomFunction) { this.randomFunction = randomFunction; return this; } sample(targetPosition, targetNormal, targetColor) { const faceIndex = this.sampleFaceIndex(); return this.sampleFace(faceIndex, targetPosition, targetNormal, targetColor); } sampleFaceIndex() { const cumulativeTotal = this.distribution[this.distribution.length - 1]; return this.binarySearch(this.randomFunction() * cumulativeTotal); } binarySearch(x) { const dist = this.distribution; let start = 0; let end = dist.length - 1; let index = -1; while (start <= end) { const mid = Math.ceil((start + end) / 2); if (mid === 0 || dist[mid - 1] <= x && dist[mid] > x) { index = mid; break; } else if (x < dist[mid]) end = mid - 1; else start = mid + 1; } return index; } sampleFace(faceIndex, targetPosition, targetNormal, targetColor) { let u = this.randomFunction(); let v = this.randomFunction(); if (u + v > 1) { u = 1 - u; v = 1 - v; } _face.a.fromBufferAttribute(this.positionAttribute, faceIndex * 3); _face.b.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 1); _face.c.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 2); targetPosition.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v)); if (targetNormal !== void 0) _face.getNormal(targetNormal); if (targetColor !== void 0 && this.colorAttribute !== void 0) { _face.a.fromBufferAttribute(this.colorAttribute, faceIndex * 3); _face.b.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 1); _face.c.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 2); _color.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v)); targetColor.r = _color.x; targetColor.g = _color.y; targetColor.b = _color.z; } return this; } }; //#endregion //#region node_modules/three-stdlib/controls/EventDispatcher.js var __defProp$16 = Object.defineProperty; var __defNormalProp$16 = (obj, key, value) => key in obj ? __defProp$16(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$16 = (obj, key, value) => { __defNormalProp$16(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var EventDispatcher$1 = class { constructor() { __publicField$16(this, "_listeners"); } /** * Adds a listener to an event type. * @param type The type of event to listen to. * @param listener The function that gets called when the event is fired. */ addEventListener(type, listener) { if (this._listeners === void 0) this._listeners = {}; const listeners = this._listeners; if (listeners[type] === void 0) listeners[type] = []; if (listeners[type].indexOf(listener) === -1) listeners[type].push(listener); } /** * Checks if listener is added to an event type. * @param type The type of event to listen to. * @param listener The function that gets called when the event is fired. */ hasEventListener(type, listener) { if (this._listeners === void 0) return false; const listeners = this._listeners; return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1; } /** * Removes a listener from an event type. * @param type The type of the listener that gets removed. * @param listener The listener function that gets removed. */ removeEventListener(type, listener) { if (this._listeners === void 0) return; const listenerArray = this._listeners[type]; if (listenerArray !== void 0) { const index = listenerArray.indexOf(listener); if (index !== -1) listenerArray.splice(index, 1); } } /** * Fire an event type. * @param event The event that gets fired. */ dispatchEvent(event) { if (this._listeners === void 0) return; const listenerArray = this._listeners[event.type]; if (listenerArray !== void 0) { event.target = this; const array = listenerArray.slice(0); for (let i = 0, l = array.length; i < l; i++) array[i].call(this, event); event.target = null; } } }; //#endregion //#region node_modules/three-stdlib/controls/FirstPersonControls.js var __defProp$15 = Object.defineProperty; var __defNormalProp$15 = (obj, key, value) => key in obj ? __defProp$15(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$15 = (obj, key, value) => { __defNormalProp$15(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var targetPosition$1 = /* @__PURE__ */ new Vector3(); var FirstPersonControls$1 = class extends EventDispatcher$1 { constructor(object, domElement) { super(); __publicField$15(this, "object"); __publicField$15(this, "domElement"); __publicField$15(this, "enabled", true); __publicField$15(this, "movementSpeed", 1); __publicField$15(this, "lookSpeed", .005); __publicField$15(this, "lookVertical", true); __publicField$15(this, "autoForward", false); __publicField$15(this, "activeLook", true); __publicField$15(this, "heightSpeed", false); __publicField$15(this, "heightCoef", 1); __publicField$15(this, "heightMin", 0); __publicField$15(this, "heightMax", 1); __publicField$15(this, "constrainVertical", false); __publicField$15(this, "verticalMin", 0); __publicField$15(this, "verticalMax", Math.PI); __publicField$15(this, "mouseDragOn", false); __publicField$15(this, "autoSpeedFactor", 0); __publicField$15(this, "mouseX", 0); __publicField$15(this, "mouseY", 0); __publicField$15(this, "moveForward", false); __publicField$15(this, "moveBackward", false); __publicField$15(this, "moveLeft", false); __publicField$15(this, "moveRight", false); __publicField$15(this, "moveUp", false); __publicField$15(this, "moveDown", false); __publicField$15(this, "viewHalfX", 0); __publicField$15(this, "viewHalfY", 0); __publicField$15(this, "lat", 0); __publicField$15(this, "lon", 0); __publicField$15(this, "lookDirection", new Vector3()); __publicField$15(this, "spherical", new Spherical()); __publicField$15(this, "target", new Vector3()); __publicField$15(this, "connect", (domElement) => { domElement.setAttribute("tabindex", "-1"); domElement.style.touchAction = "none"; domElement.addEventListener("contextmenu", this.contextmenu); domElement.addEventListener("mousemove", this.onMouseMove); domElement.addEventListener("mousedown", this.onMouseDown); domElement.addEventListener("mouseup", this.onMouseUp); this.domElement = domElement; window.addEventListener("keydown", this.onKeyDown); window.addEventListener("keyup", this.onKeyUp); this.handleResize(); }); __publicField$15(this, "dispose", () => { var _a, _b, _c, _d; (_a = this.domElement) == null || _a.removeEventListener("contextmenu", this.contextmenu); (_b = this.domElement) == null || _b.removeEventListener("mousedown", this.onMouseDown); (_c = this.domElement) == null || _c.removeEventListener("mousemove", this.onMouseMove); (_d = this.domElement) == null || _d.removeEventListener("mouseup", this.onMouseUp); window.removeEventListener("keydown", this.onKeyDown); window.removeEventListener("keyup", this.onKeyUp); }); __publicField$15(this, "handleResize", () => { if (this.domElement) { this.viewHalfX = this.domElement.offsetWidth / 2; this.viewHalfY = this.domElement.offsetHeight / 2; } }); __publicField$15(this, "onMouseDown", (event) => { var _a; (_a = this.domElement) == null || _a.focus(); if (this.activeLook) switch (event.button) { case 0: this.moveForward = true; break; case 2: this.moveBackward = true; break; } this.mouseDragOn = true; }); __publicField$15(this, "onMouseUp", (event) => { if (this.activeLook) switch (event.button) { case 0: this.moveForward = false; break; case 2: this.moveBackward = false; break; } this.mouseDragOn = false; }); __publicField$15(this, "onMouseMove", (event) => { if (this.domElement) { this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX; this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY; } }); __publicField$15(this, "onKeyDown", (event) => { switch (event.code) { case "ArrowUp": case "KeyW": this.moveForward = true; break; case "ArrowLeft": case "KeyA": this.moveLeft = true; break; case "ArrowDown": case "KeyS": this.moveBackward = true; break; case "ArrowRight": case "KeyD": this.moveRight = true; break; case "KeyR": this.moveUp = true; break; case "KeyF": this.moveDown = true; break; } }); __publicField$15(this, "onKeyUp", (event) => { switch (event.code) { case "ArrowUp": case "KeyW": this.moveForward = false; break; case "ArrowLeft": case "KeyA": this.moveLeft = false; break; case "ArrowDown": case "KeyS": this.moveBackward = false; break; case "ArrowRight": case "KeyD": this.moveRight = false; break; case "KeyR": this.moveUp = false; break; case "KeyF": this.moveDown = false; break; } }); __publicField$15(this, "lookAt", (x, y, z) => { if (x instanceof Vector3) this.target.copy(x); else if (y && z) this.target.set(x, y, z); this.object.lookAt(this.target); this.setOrientation(); return this; }); __publicField$15(this, "update", (delta) => { if (!this.enabled) return; if (this.heightSpeed) { const heightDelta = MathUtils.clamp(this.object.position.y, this.heightMin, this.heightMax) - this.heightMin; this.autoSpeedFactor = delta * (heightDelta * this.heightCoef); } else this.autoSpeedFactor = 0; const actualMoveSpeed = delta * this.movementSpeed; if (this.moveForward || this.autoForward && !this.moveBackward) this.object.translateZ(-(actualMoveSpeed + this.autoSpeedFactor)); if (this.moveBackward) this.object.translateZ(actualMoveSpeed); if (this.moveLeft) this.object.translateX(-actualMoveSpeed); if (this.moveRight) this.object.translateX(actualMoveSpeed); if (this.moveUp) this.object.translateY(actualMoveSpeed); if (this.moveDown) this.object.translateY(-actualMoveSpeed); let actualLookSpeed = delta * this.lookSpeed; if (!this.activeLook) actualLookSpeed = 0; let verticalLookRatio = 1; if (this.constrainVertical) verticalLookRatio = Math.PI / (this.verticalMax - this.verticalMin); this.lon -= this.mouseX * actualLookSpeed; if (this.lookVertical) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio; this.lat = Math.max(-85, Math.min(85, this.lat)); let phi = MathUtils.degToRad(90 - this.lat); const theta = MathUtils.degToRad(this.lon); if (this.constrainVertical) phi = MathUtils.mapLinear(phi, 0, Math.PI, this.verticalMin, this.verticalMax); const position = this.object.position; targetPosition$1.setFromSphericalCoords(1, phi, theta).add(position); this.object.lookAt(targetPosition$1); }); __publicField$15(this, "contextmenu", (event) => event.preventDefault()); __publicField$15(this, "setOrientation", () => { this.lookDirection.set(0, 0, -1).applyQuaternion(this.object.quaternion); this.spherical.setFromVector3(this.lookDirection); this.lat = 90 - MathUtils.radToDeg(this.spherical.phi); this.lon = MathUtils.radToDeg(this.spherical.theta); }); this.object = object; this.domElement = domElement; this.setOrientation(); if (domElement) this.connect(domElement); } }; //#endregion //#region node_modules/three-stdlib/controls/TransformControls.js var __defProp$14 = Object.defineProperty; var __defNormalProp$14 = (obj, key, value) => key in obj ? __defProp$14(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$14 = (obj, key, value) => { __defNormalProp$14(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var TransformControls$1 = class extends Object3D { constructor(camera, domElement) { super(); __publicField$14(this, "isTransformControls", true); __publicField$14(this, "visible", false); __publicField$14(this, "domElement"); __publicField$14(this, "raycaster", new Raycaster()); __publicField$14(this, "gizmo"); __publicField$14(this, "plane"); __publicField$14(this, "tempVector", new Vector3()); __publicField$14(this, "tempVector2", new Vector3()); __publicField$14(this, "tempQuaternion", new Quaternion()); __publicField$14(this, "unit", { X: new Vector3(1, 0, 0), Y: new Vector3(0, 1, 0), Z: new Vector3(0, 0, 1) }); __publicField$14(this, "pointStart", new Vector3()); __publicField$14(this, "pointEnd", new Vector3()); __publicField$14(this, "offset", new Vector3()); __publicField$14(this, "rotationAxis", new Vector3()); __publicField$14(this, "startNorm", new Vector3()); __publicField$14(this, "endNorm", new Vector3()); __publicField$14(this, "rotationAngle", 0); __publicField$14(this, "cameraPosition", new Vector3()); __publicField$14(this, "cameraQuaternion", new Quaternion()); __publicField$14(this, "cameraScale", new Vector3()); __publicField$14(this, "parentPosition", new Vector3()); __publicField$14(this, "parentQuaternion", new Quaternion()); __publicField$14(this, "parentQuaternionInv", new Quaternion()); __publicField$14(this, "parentScale", new Vector3()); __publicField$14(this, "worldPositionStart", new Vector3()); __publicField$14(this, "worldQuaternionStart", new Quaternion()); __publicField$14(this, "worldScaleStart", new Vector3()); __publicField$14(this, "worldPosition", new Vector3()); __publicField$14(this, "worldQuaternion", new Quaternion()); __publicField$14(this, "worldQuaternionInv", new Quaternion()); __publicField$14(this, "worldScale", new Vector3()); __publicField$14(this, "eye", new Vector3()); __publicField$14(this, "positionStart", new Vector3()); __publicField$14(this, "quaternionStart", new Quaternion()); __publicField$14(this, "scaleStart", new Vector3()); __publicField$14(this, "camera"); __publicField$14(this, "object"); __publicField$14(this, "enabled", true); __publicField$14(this, "axis", null); __publicField$14(this, "mode", "translate"); __publicField$14(this, "translationSnap", null); __publicField$14(this, "rotationSnap", null); __publicField$14(this, "scaleSnap", null); __publicField$14(this, "space", "world"); __publicField$14(this, "size", 1); __publicField$14(this, "dragging", false); __publicField$14(this, "showX", true); __publicField$14(this, "showY", true); __publicField$14(this, "showZ", true); __publicField$14(this, "changeEvent", { type: "change" }); __publicField$14(this, "mouseDownEvent", { type: "mouseDown", mode: this.mode }); __publicField$14(this, "mouseUpEvent", { type: "mouseUp", mode: this.mode }); __publicField$14(this, "objectChangeEvent", { type: "objectChange" }); __publicField$14(this, "intersectObjectWithRay", (object, raycaster, includeInvisible) => { const allIntersections = raycaster.intersectObject(object, true); for (let i = 0; i < allIntersections.length; i++) if (allIntersections[i].object.visible || includeInvisible) return allIntersections[i]; return false; }); __publicField$14(this, "attach", (object) => { this.object = object; this.visible = true; return this; }); __publicField$14(this, "detach", () => { this.object = void 0; this.visible = false; this.axis = null; return this; }); __publicField$14(this, "reset", () => { if (!this.enabled) return this; if (this.dragging) { if (this.object !== void 0) { this.object.position.copy(this.positionStart); this.object.quaternion.copy(this.quaternionStart); this.object.scale.copy(this.scaleStart); this.dispatchEvent(this.changeEvent); this.dispatchEvent(this.objectChangeEvent); this.pointStart.copy(this.pointEnd); } } return this; }); __publicField$14(this, "updateMatrixWorld", () => { if (this.object !== void 0) { this.object.updateMatrixWorld(); if (this.object.parent === null) console.error("TransformControls: The attached 3D object must be a part of the scene graph."); else this.object.parent.matrixWorld.decompose(this.parentPosition, this.parentQuaternion, this.parentScale); this.object.matrixWorld.decompose(this.worldPosition, this.worldQuaternion, this.worldScale); this.parentQuaternionInv.copy(this.parentQuaternion).invert(); this.worldQuaternionInv.copy(this.worldQuaternion).invert(); } this.camera.updateMatrixWorld(); this.camera.matrixWorld.decompose(this.cameraPosition, this.cameraQuaternion, this.cameraScale); this.eye.copy(this.cameraPosition).sub(this.worldPosition).normalize(); super.updateMatrixWorld(); }); __publicField$14(this, "pointerHover", (pointer) => { if (this.object === void 0 || this.dragging === true) return; this.raycaster.setFromCamera(pointer, this.camera); const intersect = this.intersectObjectWithRay(this.gizmo.picker[this.mode], this.raycaster); if (intersect) this.axis = intersect.object.name; else this.axis = null; }); __publicField$14(this, "pointerDown", (pointer) => { if (this.object === void 0 || this.dragging === true || pointer.button !== 0) return; if (this.axis !== null) { this.raycaster.setFromCamera(pointer, this.camera); const planeIntersect = this.intersectObjectWithRay(this.plane, this.raycaster, true); if (planeIntersect) { let space = this.space; if (this.mode === "scale") space = "local"; else if (this.axis === "E" || this.axis === "XYZE" || this.axis === "XYZ") space = "world"; if (space === "local" && this.mode === "rotate") { const snap = this.rotationSnap; if (this.axis === "X" && snap) this.object.rotation.x = Math.round(this.object.rotation.x / snap) * snap; if (this.axis === "Y" && snap) this.object.rotation.y = Math.round(this.object.rotation.y / snap) * snap; if (this.axis === "Z" && snap) this.object.rotation.z = Math.round(this.object.rotation.z / snap) * snap; } this.object.updateMatrixWorld(); if (this.object.parent) this.object.parent.updateMatrixWorld(); this.positionStart.copy(this.object.position); this.quaternionStart.copy(this.object.quaternion); this.scaleStart.copy(this.object.scale); this.object.matrixWorld.decompose(this.worldPositionStart, this.worldQuaternionStart, this.worldScaleStart); this.pointStart.copy(planeIntersect.point).sub(this.worldPositionStart); } this.dragging = true; this.mouseDownEvent.mode = this.mode; this.dispatchEvent(this.mouseDownEvent); } }); __publicField$14(this, "pointerMove", (pointer) => { const axis = this.axis; const mode = this.mode; const object = this.object; let space = this.space; if (mode === "scale") space = "local"; else if (axis === "E" || axis === "XYZE" || axis === "XYZ") space = "world"; if (object === void 0 || axis === null || this.dragging === false || pointer.button !== -1) return; this.raycaster.setFromCamera(pointer, this.camera); const planeIntersect = this.intersectObjectWithRay(this.plane, this.raycaster, true); if (!planeIntersect) return; this.pointEnd.copy(planeIntersect.point).sub(this.worldPositionStart); if (mode === "translate") { this.offset.copy(this.pointEnd).sub(this.pointStart); if (space === "local" && axis !== "XYZ") this.offset.applyQuaternion(this.worldQuaternionInv); if (axis.indexOf("X") === -1) this.offset.x = 0; if (axis.indexOf("Y") === -1) this.offset.y = 0; if (axis.indexOf("Z") === -1) this.offset.z = 0; if (space === "local" && axis !== "XYZ") this.offset.applyQuaternion(this.quaternionStart).divide(this.parentScale); else this.offset.applyQuaternion(this.parentQuaternionInv).divide(this.parentScale); object.position.copy(this.offset).add(this.positionStart); if (this.translationSnap) { if (space === "local") { object.position.applyQuaternion(this.tempQuaternion.copy(this.quaternionStart).invert()); if (axis.search("X") !== -1) object.position.x = Math.round(object.position.x / this.translationSnap) * this.translationSnap; if (axis.search("Y") !== -1) object.position.y = Math.round(object.position.y / this.translationSnap) * this.translationSnap; if (axis.search("Z") !== -1) object.position.z = Math.round(object.position.z / this.translationSnap) * this.translationSnap; object.position.applyQuaternion(this.quaternionStart); } if (space === "world") { if (object.parent) object.position.add(this.tempVector.setFromMatrixPosition(object.parent.matrixWorld)); if (axis.search("X") !== -1) object.position.x = Math.round(object.position.x / this.translationSnap) * this.translationSnap; if (axis.search("Y") !== -1) object.position.y = Math.round(object.position.y / this.translationSnap) * this.translationSnap; if (axis.search("Z") !== -1) object.position.z = Math.round(object.position.z / this.translationSnap) * this.translationSnap; if (object.parent) object.position.sub(this.tempVector.setFromMatrixPosition(object.parent.matrixWorld)); } } } else if (mode === "scale") { if (axis.search("XYZ") !== -1) { let d = this.pointEnd.length() / this.pointStart.length(); if (this.pointEnd.dot(this.pointStart) < 0) d *= -1; this.tempVector2.set(d, d, d); } else { this.tempVector.copy(this.pointStart); this.tempVector2.copy(this.pointEnd); this.tempVector.applyQuaternion(this.worldQuaternionInv); this.tempVector2.applyQuaternion(this.worldQuaternionInv); this.tempVector2.divide(this.tempVector); if (axis.search("X") === -1) this.tempVector2.x = 1; if (axis.search("Y") === -1) this.tempVector2.y = 1; if (axis.search("Z") === -1) this.tempVector2.z = 1; } object.scale.copy(this.scaleStart).multiply(this.tempVector2); if (this.scaleSnap && this.object) { if (axis.search("X") !== -1) this.object.scale.x = Math.round(object.scale.x / this.scaleSnap) * this.scaleSnap || this.scaleSnap; if (axis.search("Y") !== -1) object.scale.y = Math.round(object.scale.y / this.scaleSnap) * this.scaleSnap || this.scaleSnap; if (axis.search("Z") !== -1) object.scale.z = Math.round(object.scale.z / this.scaleSnap) * this.scaleSnap || this.scaleSnap; } } else if (mode === "rotate") { this.offset.copy(this.pointEnd).sub(this.pointStart); const ROTATION_SPEED = 20 / this.worldPosition.distanceTo(this.tempVector.setFromMatrixPosition(this.camera.matrixWorld)); if (axis === "E") { this.rotationAxis.copy(this.eye); this.rotationAngle = this.pointEnd.angleTo(this.pointStart); this.startNorm.copy(this.pointStart).normalize(); this.endNorm.copy(this.pointEnd).normalize(); this.rotationAngle *= this.endNorm.cross(this.startNorm).dot(this.eye) < 0 ? 1 : -1; } else if (axis === "XYZE") { this.rotationAxis.copy(this.offset).cross(this.eye).normalize(); this.rotationAngle = this.offset.dot(this.tempVector.copy(this.rotationAxis).cross(this.eye)) * ROTATION_SPEED; } else if (axis === "X" || axis === "Y" || axis === "Z") { this.rotationAxis.copy(this.unit[axis]); this.tempVector.copy(this.unit[axis]); if (space === "local") this.tempVector.applyQuaternion(this.worldQuaternion); this.rotationAngle = this.offset.dot(this.tempVector.cross(this.eye).normalize()) * ROTATION_SPEED; } if (this.rotationSnap) this.rotationAngle = Math.round(this.rotationAngle / this.rotationSnap) * this.rotationSnap; if (space === "local" && axis !== "E" && axis !== "XYZE") { object.quaternion.copy(this.quaternionStart); object.quaternion.multiply(this.tempQuaternion.setFromAxisAngle(this.rotationAxis, this.rotationAngle)).normalize(); } else { this.rotationAxis.applyQuaternion(this.parentQuaternionInv); object.quaternion.copy(this.tempQuaternion.setFromAxisAngle(this.rotationAxis, this.rotationAngle)); object.quaternion.multiply(this.quaternionStart).normalize(); } } this.dispatchEvent(this.changeEvent); this.dispatchEvent(this.objectChangeEvent); }); __publicField$14(this, "pointerUp", (pointer) => { if (pointer.button !== 0) return; if (this.dragging && this.axis !== null) { this.mouseUpEvent.mode = this.mode; this.dispatchEvent(this.mouseUpEvent); } this.dragging = false; this.axis = null; }); __publicField$14(this, "getPointer", (event) => { var _a; if (this.domElement && ((_a = this.domElement.ownerDocument) == null ? void 0 : _a.pointerLockElement)) return { x: 0, y: 0, button: event.button }; else { const pointer = event.changedTouches ? event.changedTouches[0] : event; const rect = this.domElement.getBoundingClientRect(); return { x: (pointer.clientX - rect.left) / rect.width * 2 - 1, y: -(pointer.clientY - rect.top) / rect.height * 2 + 1, button: event.button }; } }); __publicField$14(this, "onPointerHover", (event) => { if (!this.enabled) return; switch (event.pointerType) { case "mouse": case "pen": this.pointerHover(this.getPointer(event)); break; } }); __publicField$14(this, "onPointerDown", (event) => { if (!this.enabled || !this.domElement) return; this.domElement.style.touchAction = "none"; this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove); this.pointerHover(this.getPointer(event)); this.pointerDown(this.getPointer(event)); }); __publicField$14(this, "onPointerMove", (event) => { if (!this.enabled) return; this.pointerMove(this.getPointer(event)); }); __publicField$14(this, "onPointerUp", (event) => { if (!this.enabled || !this.domElement) return; this.domElement.style.touchAction = ""; this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove); this.pointerUp(this.getPointer(event)); }); __publicField$14(this, "getMode", () => this.mode); __publicField$14(this, "setMode", (mode) => { this.mode = mode; }); __publicField$14(this, "setTranslationSnap", (translationSnap) => { this.translationSnap = translationSnap; }); __publicField$14(this, "setRotationSnap", (rotationSnap) => { this.rotationSnap = rotationSnap; }); __publicField$14(this, "setScaleSnap", (scaleSnap) => { this.scaleSnap = scaleSnap; }); __publicField$14(this, "setSize", (size) => { this.size = size; }); __publicField$14(this, "setSpace", (space) => { this.space = space; }); __publicField$14(this, "update", () => { console.warn("THREE.TransformControls: update function has no more functionality and therefore has been deprecated."); }); __publicField$14(this, "connect", (domElement) => { if (domElement === document) console.error("THREE.OrbitControls: \"document\" should not be used as the target \"domElement\". Please use \"renderer.domElement\" instead."); this.domElement = domElement; this.domElement.addEventListener("pointerdown", this.onPointerDown); this.domElement.addEventListener("pointermove", this.onPointerHover); this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp); }); __publicField$14(this, "dispose", () => { var _a, _b, _c, _d, _e, _f; (_a = this.domElement) == null || _a.removeEventListener("pointerdown", this.onPointerDown); (_b = this.domElement) == null || _b.removeEventListener("pointermove", this.onPointerHover); (_d = (_c = this.domElement) == null ? void 0 : _c.ownerDocument) == null || _d.removeEventListener("pointermove", this.onPointerMove); (_f = (_e = this.domElement) == null ? void 0 : _e.ownerDocument) == null || _f.removeEventListener("pointerup", this.onPointerUp); this.traverse((child) => { const mesh = child; if (mesh.geometry) mesh.geometry.dispose(); if (mesh.material) mesh.material.dispose(); }); }); this.domElement = domElement; this.camera = camera; this.gizmo = new TransformControlsGizmo(); this.add(this.gizmo); this.plane = new TransformControlsPlane(); this.add(this.plane); const defineProperty = (propName, defaultValue) => { let propValue = defaultValue; Object.defineProperty(this, propName, { get: function() { return propValue !== void 0 ? propValue : defaultValue; }, set: function(value) { if (propValue !== value) { propValue = value; this.plane[propName] = value; this.gizmo[propName] = value; this.dispatchEvent({ type: propName + "-changed", value }); this.dispatchEvent(this.changeEvent); } } }); this[propName] = defaultValue; this.plane[propName] = defaultValue; this.gizmo[propName] = defaultValue; }; defineProperty("camera", this.camera); defineProperty("object", this.object); defineProperty("enabled", this.enabled); defineProperty("axis", this.axis); defineProperty("mode", this.mode); defineProperty("translationSnap", this.translationSnap); defineProperty("rotationSnap", this.rotationSnap); defineProperty("scaleSnap", this.scaleSnap); defineProperty("space", this.space); defineProperty("size", this.size); defineProperty("dragging", this.dragging); defineProperty("showX", this.showX); defineProperty("showY", this.showY); defineProperty("showZ", this.showZ); defineProperty("worldPosition", this.worldPosition); defineProperty("worldPositionStart", this.worldPositionStart); defineProperty("worldQuaternion", this.worldQuaternion); defineProperty("worldQuaternionStart", this.worldQuaternionStart); defineProperty("cameraPosition", this.cameraPosition); defineProperty("cameraQuaternion", this.cameraQuaternion); defineProperty("pointStart", this.pointStart); defineProperty("pointEnd", this.pointEnd); defineProperty("rotationAxis", this.rotationAxis); defineProperty("rotationAngle", this.rotationAngle); defineProperty("eye", this.eye); if (domElement !== void 0) this.connect(domElement); } }; var TransformControlsGizmo = class extends Object3D { constructor() { super(); __publicField$14(this, "isTransformControlsGizmo", true); __publicField$14(this, "type", "TransformControlsGizmo"); __publicField$14(this, "tempVector", new Vector3(0, 0, 0)); __publicField$14(this, "tempEuler", new Euler()); __publicField$14(this, "alignVector", new Vector3(0, 1, 0)); __publicField$14(this, "zeroVector", new Vector3(0, 0, 0)); __publicField$14(this, "lookAtMatrix", new Matrix4()); __publicField$14(this, "tempQuaternion", new Quaternion()); __publicField$14(this, "tempQuaternion2", new Quaternion()); __publicField$14(this, "identityQuaternion", new Quaternion()); __publicField$14(this, "unitX", new Vector3(1, 0, 0)); __publicField$14(this, "unitY", new Vector3(0, 1, 0)); __publicField$14(this, "unitZ", new Vector3(0, 0, 1)); __publicField$14(this, "gizmo"); __publicField$14(this, "picker"); __publicField$14(this, "helper"); __publicField$14(this, "rotationAxis", new Vector3()); __publicField$14(this, "cameraPosition", new Vector3()); __publicField$14(this, "worldPositionStart", new Vector3()); __publicField$14(this, "worldQuaternionStart", new Quaternion()); __publicField$14(this, "worldPosition", new Vector3()); __publicField$14(this, "worldQuaternion", new Quaternion()); __publicField$14(this, "eye", new Vector3()); __publicField$14(this, "camera", null); __publicField$14(this, "enabled", true); __publicField$14(this, "axis", null); __publicField$14(this, "mode", "translate"); __publicField$14(this, "space", "world"); __publicField$14(this, "size", 1); __publicField$14(this, "dragging", false); __publicField$14(this, "showX", true); __publicField$14(this, "showY", true); __publicField$14(this, "showZ", true); __publicField$14(this, "updateMatrixWorld", () => { let space = this.space; if (this.mode === "scale") space = "local"; const quaternion = space === "local" ? this.worldQuaternion : this.identityQuaternion; this.gizmo["translate"].visible = this.mode === "translate"; this.gizmo["rotate"].visible = this.mode === "rotate"; this.gizmo["scale"].visible = this.mode === "scale"; this.helper["translate"].visible = this.mode === "translate"; this.helper["rotate"].visible = this.mode === "rotate"; this.helper["scale"].visible = this.mode === "scale"; let handles = []; handles = handles.concat(this.picker[this.mode].children); handles = handles.concat(this.gizmo[this.mode].children); handles = handles.concat(this.helper[this.mode].children); for (let i = 0; i < handles.length; i++) { const handle = handles[i]; handle.visible = true; handle.rotation.set(0, 0, 0); handle.position.copy(this.worldPosition); let factor; if (this.camera.isOrthographicCamera) factor = (this.camera.top - this.camera.bottom) / this.camera.zoom; else factor = this.worldPosition.distanceTo(this.cameraPosition) * Math.min(1.9 * Math.tan(Math.PI * this.camera.fov / 360) / this.camera.zoom, 7); handle.scale.set(1, 1, 1).multiplyScalar(factor * this.size / 7); if (handle.tag === "helper") { handle.visible = false; if (handle.name === "AXIS") { handle.position.copy(this.worldPositionStart); handle.visible = !!this.axis; if (this.axis === "X") { this.tempQuaternion.setFromEuler(this.tempEuler.set(0, 0, 0)); handle.quaternion.copy(quaternion).multiply(this.tempQuaternion); if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) > .9) handle.visible = false; } if (this.axis === "Y") { this.tempQuaternion.setFromEuler(this.tempEuler.set(0, 0, Math.PI / 2)); handle.quaternion.copy(quaternion).multiply(this.tempQuaternion); if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) > .9) handle.visible = false; } if (this.axis === "Z") { this.tempQuaternion.setFromEuler(this.tempEuler.set(0, Math.PI / 2, 0)); handle.quaternion.copy(quaternion).multiply(this.tempQuaternion); if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) > .9) handle.visible = false; } if (this.axis === "XYZE") { this.tempQuaternion.setFromEuler(this.tempEuler.set(0, Math.PI / 2, 0)); this.alignVector.copy(this.rotationAxis); handle.quaternion.setFromRotationMatrix(this.lookAtMatrix.lookAt(this.zeroVector, this.alignVector, this.unitY)); handle.quaternion.multiply(this.tempQuaternion); handle.visible = this.dragging; } if (this.axis === "E") handle.visible = false; } else if (handle.name === "START") { handle.position.copy(this.worldPositionStart); handle.visible = this.dragging; } else if (handle.name === "END") { handle.position.copy(this.worldPosition); handle.visible = this.dragging; } else if (handle.name === "DELTA") { handle.position.copy(this.worldPositionStart); handle.quaternion.copy(this.worldQuaternionStart); this.tempVector.set(1e-10, 1e-10, 1e-10).add(this.worldPositionStart).sub(this.worldPosition).multiplyScalar(-1); this.tempVector.applyQuaternion(this.worldQuaternionStart.clone().invert()); handle.scale.copy(this.tempVector); handle.visible = this.dragging; } else { handle.quaternion.copy(quaternion); if (this.dragging) handle.position.copy(this.worldPositionStart); else handle.position.copy(this.worldPosition); if (this.axis) handle.visible = this.axis.search(handle.name) !== -1; } continue; } handle.quaternion.copy(quaternion); if (this.mode === "translate" || this.mode === "scale") { const AXIS_HIDE_TRESHOLD = .99; const PLANE_HIDE_TRESHOLD = .2; const AXIS_FLIP_TRESHOLD = 0; if (handle.name === "X" || handle.name === "XYZX") { if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name === "Y" || handle.name === "XYZY") { if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name === "Z" || handle.name === "XYZZ") { if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name === "XY") { if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name === "YZ") { if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name === "XZ") { if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) { handle.scale.set(1e-10, 1e-10, 1e-10); handle.visible = false; } } if (handle.name.search("X") !== -1) { if (this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) if (handle.tag === "fwd") handle.visible = false; else handle.scale.x *= -1; else if (handle.tag === "bwd") handle.visible = false; } if (handle.name.search("Y") !== -1) { if (this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) if (handle.tag === "fwd") handle.visible = false; else handle.scale.y *= -1; else if (handle.tag === "bwd") handle.visible = false; } if (handle.name.search("Z") !== -1) { if (this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) if (handle.tag === "fwd") handle.visible = false; else handle.scale.z *= -1; else if (handle.tag === "bwd") handle.visible = false; } } else if (this.mode === "rotate") { this.tempQuaternion2.copy(quaternion); this.alignVector.copy(this.eye).applyQuaternion(this.tempQuaternion.copy(quaternion).invert()); if (handle.name.search("E") !== -1) handle.quaternion.setFromRotationMatrix(this.lookAtMatrix.lookAt(this.eye, this.zeroVector, this.unitY)); if (handle.name === "X") { this.tempQuaternion.setFromAxisAngle(this.unitX, Math.atan2(-this.alignVector.y, this.alignVector.z)); this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion); handle.quaternion.copy(this.tempQuaternion); } if (handle.name === "Y") { this.tempQuaternion.setFromAxisAngle(this.unitY, Math.atan2(this.alignVector.x, this.alignVector.z)); this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion); handle.quaternion.copy(this.tempQuaternion); } if (handle.name === "Z") { this.tempQuaternion.setFromAxisAngle(this.unitZ, Math.atan2(this.alignVector.y, this.alignVector.x)); this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion); handle.quaternion.copy(this.tempQuaternion); } } handle.visible = handle.visible && (handle.name.indexOf("X") === -1 || this.showX); handle.visible = handle.visible && (handle.name.indexOf("Y") === -1 || this.showY); handle.visible = handle.visible && (handle.name.indexOf("Z") === -1 || this.showZ); handle.visible = handle.visible && (handle.name.indexOf("E") === -1 || this.showX && this.showY && this.showZ); handle.material.tempOpacity = handle.material.tempOpacity || handle.material.opacity; handle.material.tempColor = handle.material.tempColor || handle.material.color.clone(); handle.material.color.copy(handle.material.tempColor); handle.material.opacity = handle.material.tempOpacity; if (!this.enabled) { handle.material.opacity *= .5; handle.material.color.lerp(new Color(1, 1, 1), .5); } else if (this.axis) if (handle.name === this.axis) { handle.material.opacity = 1; handle.material.color.lerp(new Color(1, 1, 1), .5); } else if (this.axis.split("").some(function(a) { return handle.name === a; })) { handle.material.opacity = 1; handle.material.color.lerp(new Color(1, 1, 1), .5); } else { handle.material.opacity *= .25; handle.material.color.lerp(new Color(1, 1, 1), .5); } } super.updateMatrixWorld(); }); const gizmoMaterial = new MeshBasicMaterial({ depthTest: false, depthWrite: false, transparent: true, side: 2, fog: false, toneMapped: false }); const gizmoLineMaterial = new LineBasicMaterial({ depthTest: false, depthWrite: false, transparent: true, linewidth: 1, fog: false, toneMapped: false }); const matInvisible = gizmoMaterial.clone(); matInvisible.opacity = .15; const matHelper = gizmoMaterial.clone(); matHelper.opacity = .33; const matRed = gizmoMaterial.clone(); matRed.color.set(16711680); const matGreen = gizmoMaterial.clone(); matGreen.color.set(65280); const matBlue = gizmoMaterial.clone(); matBlue.color.set(255); const matWhiteTransparent = gizmoMaterial.clone(); matWhiteTransparent.opacity = .25; const matYellowTransparent = matWhiteTransparent.clone(); matYellowTransparent.color.set(16776960); const matCyanTransparent = matWhiteTransparent.clone(); matCyanTransparent.color.set(65535); const matMagentaTransparent = matWhiteTransparent.clone(); matMagentaTransparent.color.set(16711935); gizmoMaterial.clone().color.set(16776960); const matLineRed = gizmoLineMaterial.clone(); matLineRed.color.set(16711680); const matLineGreen = gizmoLineMaterial.clone(); matLineGreen.color.set(65280); const matLineBlue = gizmoLineMaterial.clone(); matLineBlue.color.set(255); const matLineCyan = gizmoLineMaterial.clone(); matLineCyan.color.set(65535); const matLineMagenta = gizmoLineMaterial.clone(); matLineMagenta.color.set(16711935); const matLineYellow = gizmoLineMaterial.clone(); matLineYellow.color.set(16776960); const matLineGray = gizmoLineMaterial.clone(); matLineGray.color.set(7895160); const matLineYellowTransparent = matLineYellow.clone(); matLineYellowTransparent.opacity = .25; const arrowGeometry = new CylinderGeometry(0, .05, .2, 12, 1, false); const scaleHandleGeometry = new BoxGeometry(.125, .125, .125); const lineGeometry = new BufferGeometry(); lineGeometry.setAttribute("position", new Float32BufferAttribute([ 0, 0, 0, 1, 0, 0 ], 3)); const CircleGeometry = (radius, arc) => { const geometry = new BufferGeometry(); const vertices = []; for (let i = 0; i <= 64 * arc; ++i) vertices.push(0, Math.cos(i / 32 * Math.PI) * radius, Math.sin(i / 32 * Math.PI) * radius); geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3)); return geometry; }; const TranslateHelperGeometry = () => { const geometry = new BufferGeometry(); geometry.setAttribute("position", new Float32BufferAttribute([ 0, 0, 0, 1, 1, 1 ], 3)); return geometry; }; const gizmoTranslate = { X: [ [ new Mesh(arrowGeometry, matRed), [ 1, 0, 0 ], [ 0, 0, -Math.PI / 2 ], null, "fwd" ], [ new Mesh(arrowGeometry, matRed), [ 1, 0, 0 ], [ 0, 0, Math.PI / 2 ], null, "bwd" ], [new Line$1(lineGeometry, matLineRed)] ], Y: [ [ new Mesh(arrowGeometry, matGreen), [ 0, 1, 0 ], null, null, "fwd" ], [ new Mesh(arrowGeometry, matGreen), [ 0, 1, 0 ], [ Math.PI, 0, 0 ], null, "bwd" ], [ new Line$1(lineGeometry, matLineGreen), null, [ 0, 0, Math.PI / 2 ] ] ], Z: [ [ new Mesh(arrowGeometry, matBlue), [ 0, 0, 1 ], [ Math.PI / 2, 0, 0 ], null, "fwd" ], [ new Mesh(arrowGeometry, matBlue), [ 0, 0, 1 ], [ -Math.PI / 2, 0, 0 ], null, "bwd" ], [ new Line$1(lineGeometry, matLineBlue), null, [ 0, -Math.PI / 2, 0 ] ] ], XYZ: [[ new Mesh(new OctahedronGeometry(.1, 0), matWhiteTransparent.clone()), [ 0, 0, 0 ], [ 0, 0, 0 ] ]], XY: [ [new Mesh(new PlaneGeometry(.295, .295), matYellowTransparent.clone()), [ .15, .15, 0 ]], [ new Line$1(lineGeometry, matLineYellow), [ .18, .3, 0 ], null, [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineYellow), [ .3, .18, 0 ], [ 0, 0, Math.PI / 2 ], [ .125, 1, 1 ] ] ], YZ: [ [ new Mesh(new PlaneGeometry(.295, .295), matCyanTransparent.clone()), [ 0, .15, .15 ], [ 0, Math.PI / 2, 0 ] ], [ new Line$1(lineGeometry, matLineCyan), [ 0, .18, .3 ], [ 0, 0, Math.PI / 2 ], [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineCyan), [ 0, .3, .18 ], [ 0, -Math.PI / 2, 0 ], [ .125, 1, 1 ] ] ], XZ: [ [ new Mesh(new PlaneGeometry(.295, .295), matMagentaTransparent.clone()), [ .15, 0, .15 ], [ -Math.PI / 2, 0, 0 ] ], [ new Line$1(lineGeometry, matLineMagenta), [ .18, 0, .3 ], null, [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineMagenta), [ .3, 0, .18 ], [ 0, -Math.PI / 2, 0 ], [ .125, 1, 1 ] ] ] }; const pickerTranslate = { X: [[ new Mesh(new CylinderGeometry(.2, 0, 1, 4, 1, false), matInvisible), [ .6, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ]], Y: [[new Mesh(new CylinderGeometry(.2, 0, 1, 4, 1, false), matInvisible), [ 0, .6, 0 ]]], Z: [[ new Mesh(new CylinderGeometry(.2, 0, 1, 4, 1, false), matInvisible), [ 0, 0, .6 ], [ Math.PI / 2, 0, 0 ] ]], XYZ: [[new Mesh(new OctahedronGeometry(.2, 0), matInvisible)]], XY: [[new Mesh(new PlaneGeometry(.4, .4), matInvisible), [ .2, .2, 0 ]]], YZ: [[ new Mesh(new PlaneGeometry(.4, .4), matInvisible), [ 0, .2, .2 ], [ 0, Math.PI / 2, 0 ] ]], XZ: [[ new Mesh(new PlaneGeometry(.4, .4), matInvisible), [ .2, 0, .2 ], [ -Math.PI / 2, 0, 0 ] ]] }; const helperTranslate = { START: [[ new Mesh(new OctahedronGeometry(.01, 2), matHelper), null, null, null, "helper" ]], END: [[ new Mesh(new OctahedronGeometry(.01, 2), matHelper), null, null, null, "helper" ]], DELTA: [[ new Line$1(TranslateHelperGeometry(), matHelper), null, null, null, "helper" ]], X: [[ new Line$1(lineGeometry, matHelper.clone()), [ -1e3, 0, 0 ], null, [ 1e6, 1, 1 ], "helper" ]], Y: [[ new Line$1(lineGeometry, matHelper.clone()), [ 0, -1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], "helper" ]], Z: [[ new Line$1(lineGeometry, matHelper.clone()), [ 0, 0, -1e3 ], [ 0, -Math.PI / 2, 0 ], [ 1e6, 1, 1 ], "helper" ]] }; const gizmoRotate = { X: [[new Line$1(CircleGeometry(1, .5), matLineRed)], [ new Mesh(new OctahedronGeometry(.04, 0), matRed), [ 0, 0, .99 ], null, [ 1, 3, 1 ] ]], Y: [[ new Line$1(CircleGeometry(1, .5), matLineGreen), null, [ 0, 0, -Math.PI / 2 ] ], [ new Mesh(new OctahedronGeometry(.04, 0), matGreen), [ 0, 0, .99 ], null, [ 3, 1, 1 ] ]], Z: [[ new Line$1(CircleGeometry(1, .5), matLineBlue), null, [ 0, Math.PI / 2, 0 ] ], [ new Mesh(new OctahedronGeometry(.04, 0), matBlue), [ .99, 0, 0 ], null, [ 1, 3, 1 ] ]], E: [ [ new Line$1(CircleGeometry(1.25, 1), matLineYellowTransparent), null, [ 0, Math.PI / 2, 0 ] ], [ new Mesh(new CylinderGeometry(.03, 0, .15, 4, 1, false), matLineYellowTransparent), [ 1.17, 0, 0 ], [ 0, 0, -Math.PI / 2 ], [ 1, 1, .001 ] ], [ new Mesh(new CylinderGeometry(.03, 0, .15, 4, 1, false), matLineYellowTransparent), [ -1.17, 0, 0 ], [ 0, 0, Math.PI / 2 ], [ 1, 1, .001 ] ], [ new Mesh(new CylinderGeometry(.03, 0, .15, 4, 1, false), matLineYellowTransparent), [ 0, -1.17, 0 ], [ Math.PI, 0, 0 ], [ 1, 1, .001 ] ], [ new Mesh(new CylinderGeometry(.03, 0, .15, 4, 1, false), matLineYellowTransparent), [ 0, 1.17, 0 ], [ 0, 0, 0 ], [ 1, 1, .001 ] ] ], XYZE: [[ new Line$1(CircleGeometry(1, 1), matLineGray), null, [ 0, Math.PI / 2, 0 ] ]] }; const helperRotate = { AXIS: [[ new Line$1(lineGeometry, matHelper.clone()), [ -1e3, 0, 0 ], null, [ 1e6, 1, 1 ], "helper" ]] }; const pickerRotate = { X: [[ new Mesh(new TorusGeometry(1, .1, 4, 24), matInvisible), [ 0, 0, 0 ], [ 0, -Math.PI / 2, -Math.PI / 2 ] ]], Y: [[ new Mesh(new TorusGeometry(1, .1, 4, 24), matInvisible), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ] ]], Z: [[ new Mesh(new TorusGeometry(1, .1, 4, 24), matInvisible), [ 0, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ]], E: [[new Mesh(new TorusGeometry(1.25, .1, 2, 24), matInvisible)]], XYZE: [[new Mesh(new SphereGeometry(.7, 10, 8), matInvisible)]] }; const gizmoScale = { X: [[ new Mesh(scaleHandleGeometry, matRed), [ .8, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ], [ new Line$1(lineGeometry, matLineRed), null, null, [ .8, 1, 1 ] ]], Y: [[new Mesh(scaleHandleGeometry, matGreen), [ 0, .8, 0 ]], [ new Line$1(lineGeometry, matLineGreen), null, [ 0, 0, Math.PI / 2 ], [ .8, 1, 1 ] ]], Z: [[ new Mesh(scaleHandleGeometry, matBlue), [ 0, 0, .8 ], [ Math.PI / 2, 0, 0 ] ], [ new Line$1(lineGeometry, matLineBlue), null, [ 0, -Math.PI / 2, 0 ], [ .8, 1, 1 ] ]], XY: [ [ new Mesh(scaleHandleGeometry, matYellowTransparent), [ .85, .85, 0 ], null, [ 2, 2, .2 ] ], [ new Line$1(lineGeometry, matLineYellow), [ .855, .98, 0 ], null, [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineYellow), [ .98, .855, 0 ], [ 0, 0, Math.PI / 2 ], [ .125, 1, 1 ] ] ], YZ: [ [ new Mesh(scaleHandleGeometry, matCyanTransparent), [ 0, .85, .85 ], null, [ .2, 2, 2 ] ], [ new Line$1(lineGeometry, matLineCyan), [ 0, .855, .98 ], [ 0, 0, Math.PI / 2 ], [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineCyan), [ 0, .98, .855 ], [ 0, -Math.PI / 2, 0 ], [ .125, 1, 1 ] ] ], XZ: [ [ new Mesh(scaleHandleGeometry, matMagentaTransparent), [ .85, 0, .85 ], null, [ 2, .2, 2 ] ], [ new Line$1(lineGeometry, matLineMagenta), [ .855, 0, .98 ], null, [ .125, 1, 1 ] ], [ new Line$1(lineGeometry, matLineMagenta), [ .98, 0, .855 ], [ 0, -Math.PI / 2, 0 ], [ .125, 1, 1 ] ] ], XYZX: [[new Mesh(new BoxGeometry(.125, .125, .125), matWhiteTransparent.clone()), [ 1.1, 0, 0 ]]], XYZY: [[new Mesh(new BoxGeometry(.125, .125, .125), matWhiteTransparent.clone()), [ 0, 1.1, 0 ]]], XYZZ: [[new Mesh(new BoxGeometry(.125, .125, .125), matWhiteTransparent.clone()), [ 0, 0, 1.1 ]]] }; const pickerScale = { X: [[ new Mesh(new CylinderGeometry(.2, 0, .8, 4, 1, false), matInvisible), [ .5, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ]], Y: [[new Mesh(new CylinderGeometry(.2, 0, .8, 4, 1, false), matInvisible), [ 0, .5, 0 ]]], Z: [[ new Mesh(new CylinderGeometry(.2, 0, .8, 4, 1, false), matInvisible), [ 0, 0, .5 ], [ Math.PI / 2, 0, 0 ] ]], XY: [[ new Mesh(scaleHandleGeometry, matInvisible), [ .85, .85, 0 ], null, [ 3, 3, .2 ] ]], YZ: [[ new Mesh(scaleHandleGeometry, matInvisible), [ 0, .85, .85 ], null, [ .2, 3, 3 ] ]], XZ: [[ new Mesh(scaleHandleGeometry, matInvisible), [ .85, 0, .85 ], null, [ 3, .2, 3 ] ]], XYZX: [[new Mesh(new BoxGeometry(.2, .2, .2), matInvisible), [ 1.1, 0, 0 ]]], XYZY: [[new Mesh(new BoxGeometry(.2, .2, .2), matInvisible), [ 0, 1.1, 0 ]]], XYZZ: [[new Mesh(new BoxGeometry(.2, .2, .2), matInvisible), [ 0, 0, 1.1 ]]] }; const helperScale = { X: [[ new Line$1(lineGeometry, matHelper.clone()), [ -1e3, 0, 0 ], null, [ 1e6, 1, 1 ], "helper" ]], Y: [[ new Line$1(lineGeometry, matHelper.clone()), [ 0, -1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], "helper" ]], Z: [[ new Line$1(lineGeometry, matHelper.clone()), [ 0, 0, -1e3 ], [ 0, -Math.PI / 2, 0 ], [ 1e6, 1, 1 ], "helper" ]] }; const setupGizmo = (gizmoMap) => { const gizmo = new Object3D(); for (let name in gizmoMap) for (let i = gizmoMap[name].length; i--;) { const object = gizmoMap[name][i][0].clone(); const position = gizmoMap[name][i][1]; const rotation = gizmoMap[name][i][2]; const scale = gizmoMap[name][i][3]; const tag = gizmoMap[name][i][4]; object.name = name; object.tag = tag; if (position) object.position.set(position[0], position[1], position[2]); if (rotation) object.rotation.set(rotation[0], rotation[1], rotation[2]); if (scale) object.scale.set(scale[0], scale[1], scale[2]); object.updateMatrix(); const tempGeometry = object.geometry.clone(); tempGeometry.applyMatrix4(object.matrix); object.geometry = tempGeometry; object.renderOrder = Infinity; object.position.set(0, 0, 0); object.rotation.set(0, 0, 0); object.scale.set(1, 1, 1); gizmo.add(object); } return gizmo; }; this.gizmo = {}; this.picker = {}; this.helper = {}; this.add(this.gizmo["translate"] = setupGizmo(gizmoTranslate)); this.add(this.gizmo["rotate"] = setupGizmo(gizmoRotate)); this.add(this.gizmo["scale"] = setupGizmo(gizmoScale)); this.add(this.picker["translate"] = setupGizmo(pickerTranslate)); this.add(this.picker["rotate"] = setupGizmo(pickerRotate)); this.add(this.picker["scale"] = setupGizmo(pickerScale)); this.add(this.helper["translate"] = setupGizmo(helperTranslate)); this.add(this.helper["rotate"] = setupGizmo(helperRotate)); this.add(this.helper["scale"] = setupGizmo(helperScale)); this.picker["translate"].visible = false; this.picker["rotate"].visible = false; this.picker["scale"].visible = false; } }; var TransformControlsPlane = class extends Mesh { constructor() { super(new PlaneGeometry(1e5, 1e5, 2, 2), new MeshBasicMaterial({ visible: false, wireframe: true, side: 2, transparent: true, opacity: .1, toneMapped: false })); __publicField$14(this, "isTransformControlsPlane", true); __publicField$14(this, "type", "TransformControlsPlane"); __publicField$14(this, "unitX", new Vector3(1, 0, 0)); __publicField$14(this, "unitY", new Vector3(0, 1, 0)); __publicField$14(this, "unitZ", new Vector3(0, 0, 1)); __publicField$14(this, "tempVector", new Vector3()); __publicField$14(this, "dirVector", new Vector3()); __publicField$14(this, "alignVector", new Vector3()); __publicField$14(this, "tempMatrix", new Matrix4()); __publicField$14(this, "identityQuaternion", new Quaternion()); __publicField$14(this, "cameraQuaternion", new Quaternion()); __publicField$14(this, "worldPosition", new Vector3()); __publicField$14(this, "worldQuaternion", new Quaternion()); __publicField$14(this, "eye", new Vector3()); __publicField$14(this, "axis", null); __publicField$14(this, "mode", "translate"); __publicField$14(this, "space", "world"); __publicField$14(this, "updateMatrixWorld", () => { let space = this.space; this.position.copy(this.worldPosition); if (this.mode === "scale") space = "local"; this.unitX.set(1, 0, 0).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion); this.unitY.set(0, 1, 0).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion); this.unitZ.set(0, 0, 1).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion); this.alignVector.copy(this.unitY); switch (this.mode) { case "translate": case "scale": switch (this.axis) { case "X": this.alignVector.copy(this.eye).cross(this.unitX); this.dirVector.copy(this.unitX).cross(this.alignVector); break; case "Y": this.alignVector.copy(this.eye).cross(this.unitY); this.dirVector.copy(this.unitY).cross(this.alignVector); break; case "Z": this.alignVector.copy(this.eye).cross(this.unitZ); this.dirVector.copy(this.unitZ).cross(this.alignVector); break; case "XY": this.dirVector.copy(this.unitZ); break; case "YZ": this.dirVector.copy(this.unitX); break; case "XZ": this.alignVector.copy(this.unitZ); this.dirVector.copy(this.unitY); break; case "XYZ": case "E": this.dirVector.set(0, 0, 0); break; } break; default: this.dirVector.set(0, 0, 0); } if (this.dirVector.length() === 0) this.quaternion.copy(this.cameraQuaternion); else { this.tempMatrix.lookAt(this.tempVector.set(0, 0, 0), this.dirVector, this.alignVector); this.quaternion.setFromRotationMatrix(this.tempMatrix); } super.updateMatrixWorld(); }); } }; //#endregion //#region node_modules/three-stdlib/controls/PointerLockControls.js var __defProp$13 = Object.defineProperty; var __defNormalProp$13 = (obj, key, value) => key in obj ? __defProp$13(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$13 = (obj, key, value) => { __defNormalProp$13(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var _euler = /* @__PURE__ */ new Euler(0, 0, 0, "YXZ"); var _vector$1 = /* @__PURE__ */ new Vector3(); var _changeEvent$1 = { type: "change" }; var _lockEvent = { type: "lock" }; var _unlockEvent = { type: "unlock" }; var _MOUSE_SENSITIVITY = .002; var _PI_2 = Math.PI / 2; var PointerLockControls$1 = class extends EventDispatcher$1 { constructor(camera, domElement) { super(); __publicField$13(this, "camera"); __publicField$13(this, "domElement"); __publicField$13(this, "isLocked"); __publicField$13(this, "minPolarAngle"); __publicField$13(this, "maxPolarAngle"); __publicField$13(this, "pointerSpeed"); __publicField$13(this, "onMouseMove", (event) => { if (!this.domElement || this.isLocked === false) return; _euler.setFromQuaternion(this.camera.quaternion); _euler.y -= event.movementX * _MOUSE_SENSITIVITY * this.pointerSpeed; _euler.x -= event.movementY * _MOUSE_SENSITIVITY * this.pointerSpeed; _euler.x = Math.max(_PI_2 - this.maxPolarAngle, Math.min(_PI_2 - this.minPolarAngle, _euler.x)); this.camera.quaternion.setFromEuler(_euler); this.dispatchEvent(_changeEvent$1); }); __publicField$13(this, "onPointerlockChange", () => { if (!this.domElement) return; if (this.domElement.ownerDocument.pointerLockElement === this.domElement) { this.dispatchEvent(_lockEvent); this.isLocked = true; } else { this.dispatchEvent(_unlockEvent); this.isLocked = false; } }); __publicField$13(this, "onPointerlockError", () => { console.error("THREE.PointerLockControls: Unable to use Pointer Lock API"); }); __publicField$13(this, "connect", (domElement) => { this.domElement = domElement || this.domElement; if (!this.domElement) return; this.domElement.ownerDocument.addEventListener("mousemove", this.onMouseMove); this.domElement.ownerDocument.addEventListener("pointerlockchange", this.onPointerlockChange); this.domElement.ownerDocument.addEventListener("pointerlockerror", this.onPointerlockError); }); __publicField$13(this, "disconnect", () => { if (!this.domElement) return; this.domElement.ownerDocument.removeEventListener("mousemove", this.onMouseMove); this.domElement.ownerDocument.removeEventListener("pointerlockchange", this.onPointerlockChange); this.domElement.ownerDocument.removeEventListener("pointerlockerror", this.onPointerlockError); }); __publicField$13(this, "dispose", () => { this.disconnect(); }); __publicField$13(this, "getObject", () => { return this.camera; }); __publicField$13(this, "direction", new Vector3(0, 0, -1)); __publicField$13(this, "getDirection", (v) => { return v.copy(this.direction).applyQuaternion(this.camera.quaternion); }); __publicField$13(this, "moveForward", (distance) => { _vector$1.setFromMatrixColumn(this.camera.matrix, 0); _vector$1.crossVectors(this.camera.up, _vector$1); this.camera.position.addScaledVector(_vector$1, distance); }); __publicField$13(this, "moveRight", (distance) => { _vector$1.setFromMatrixColumn(this.camera.matrix, 0); this.camera.position.addScaledVector(_vector$1, distance); }); __publicField$13(this, "lock", () => { if (this.domElement) this.domElement.requestPointerLock(); }); __publicField$13(this, "unlock", () => { if (this.domElement) this.domElement.ownerDocument.exitPointerLock(); }); this.camera = camera; this.domElement = domElement; this.isLocked = false; this.minPolarAngle = 0; this.maxPolarAngle = Math.PI; this.pointerSpeed = 1; if (domElement) this.connect(domElement); } }; //#endregion //#region node_modules/three-stdlib/controls/DeviceOrientationControls.js var __defProp$12 = Object.defineProperty; var __defNormalProp$12 = (obj, key, value) => key in obj ? __defProp$12(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$12 = (obj, key, value) => { __defNormalProp$12(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var DeviceOrientationControls$1 = class extends EventDispatcher$1 { constructor(object) { super(); __publicField$12(this, "object"); __publicField$12(this, "changeEvent", { type: "change" }); __publicField$12(this, "EPS", 1e-6); __publicField$12(this, "enabled", true); __publicField$12(this, "deviceOrientation", { alpha: 0, beta: 0, gamma: 0 }); __publicField$12(this, "screenOrientation", 0); __publicField$12(this, "alphaOffset", 0); __publicField$12(this, "onDeviceOrientationChangeEvent", (event) => { this.deviceOrientation = event; }); __publicField$12(this, "onScreenOrientationChangeEvent", () => { this.screenOrientation = window.orientation || 0; }); __publicField$12(this, "zee", new Vector3(0, 0, 1)); __publicField$12(this, "euler", new Euler()); __publicField$12(this, "q0", new Quaternion()); __publicField$12(this, "q1", new Quaternion(-Math.sqrt(.5), 0, 0, Math.sqrt(.5))); __publicField$12(this, "setObjectQuaternion", (quaternion, alpha, beta, gamma, orient) => { this.euler.set(beta, alpha, -gamma, "YXZ"); quaternion.setFromEuler(this.euler); quaternion.multiply(this.q1); quaternion.multiply(this.q0.setFromAxisAngle(this.zee, -orient)); }); __publicField$12(this, "connect", () => { this.onScreenOrientationChangeEvent(); if (window.DeviceOrientationEvent !== void 0 && typeof window.DeviceOrientationEvent.requestPermission === "function") window.DeviceOrientationEvent.requestPermission().then((response) => { if (response == "granted") { window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent); window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent); } }).catch((error) => { console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:", error); }); else { window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent); window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent); } this.enabled = true; }); __publicField$12(this, "disconnect", () => { window.removeEventListener("orientationchange", this.onScreenOrientationChangeEvent); window.removeEventListener("deviceorientation", this.onDeviceOrientationChangeEvent); this.enabled = false; }); __publicField$12(this, "lastQuaternion", new Quaternion()); __publicField$12(this, "update", () => { if (this.enabled === false) return; const device = this.deviceOrientation; if (device) { const alpha = device.alpha ? MathUtils.degToRad(device.alpha) + this.alphaOffset : 0; const beta = device.beta ? MathUtils.degToRad(device.beta) : 0; const gamma = device.gamma ? MathUtils.degToRad(device.gamma) : 0; const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation) : 0; this.setObjectQuaternion(this.object.quaternion, alpha, beta, gamma, orient); if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) { this.lastQuaternion.copy(this.object.quaternion); this.dispatchEvent(this.changeEvent); } } }); __publicField$12(this, "dispose", () => this.disconnect()); this.object = object; this.object.rotation.reorder("YXZ"); this.connect(); } }; //#endregion //#region node_modules/three-stdlib/controls/TrackballControls.js var __defProp$11 = Object.defineProperty; var __defNormalProp$11 = (obj, key, value) => key in obj ? __defProp$11(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$11 = (obj, key, value) => { __defNormalProp$11(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var TrackballControls$1 = class extends EventDispatcher$1 { constructor(object, domElement) { super(); __publicField$11(this, "enabled", true); __publicField$11(this, "screen", { left: 0, top: 0, width: 0, height: 0 }); __publicField$11(this, "rotateSpeed", 1); __publicField$11(this, "zoomSpeed", 1.2); __publicField$11(this, "panSpeed", .3); __publicField$11(this, "noRotate", false); __publicField$11(this, "noZoom", false); __publicField$11(this, "noPan", false); __publicField$11(this, "staticMoving", false); __publicField$11(this, "dynamicDampingFactor", .2); __publicField$11(this, "minDistance", 0); __publicField$11(this, "maxDistance", Infinity); __publicField$11(this, "keys", [ "KeyA", "KeyS", "KeyD" ]); __publicField$11(this, "mouseButtons", { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }); __publicField$11(this, "object"); __publicField$11(this, "domElement"); __publicField$11(this, "cursorZoom", false); __publicField$11(this, "target", new Vector3()); __publicField$11(this, "mousePosition", new Vector2()); __publicField$11(this, "STATE", { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }); __publicField$11(this, "EPS", 1e-6); __publicField$11(this, "lastZoom", 1); __publicField$11(this, "lastPosition", new Vector3()); __publicField$11(this, "cursorVector", new Vector3()); __publicField$11(this, "targetVector", new Vector3()); __publicField$11(this, "_state", this.STATE.NONE); __publicField$11(this, "_keyState", this.STATE.NONE); __publicField$11(this, "_eye", new Vector3()); __publicField$11(this, "_movePrev", new Vector2()); __publicField$11(this, "_moveCurr", new Vector2()); __publicField$11(this, "_lastAxis", new Vector3()); __publicField$11(this, "_lastAngle", 0); __publicField$11(this, "_zoomStart", new Vector2()); __publicField$11(this, "_zoomEnd", new Vector2()); __publicField$11(this, "_touchZoomDistanceStart", 0); __publicField$11(this, "_touchZoomDistanceEnd", 0); __publicField$11(this, "_panStart", new Vector2()); __publicField$11(this, "_panEnd", new Vector2()); __publicField$11(this, "target0"); __publicField$11(this, "position0"); __publicField$11(this, "up0"); __publicField$11(this, "zoom0"); __publicField$11(this, "changeEvent", { type: "change" }); __publicField$11(this, "startEvent", { type: "start" }); __publicField$11(this, "endEvent", { type: "end" }); __publicField$11(this, "onScreenVector", new Vector2()); __publicField$11(this, "getMouseOnScreen", (pageX, pageY) => { this.onScreenVector.set((pageX - this.screen.left) / this.screen.width, (pageY - this.screen.top) / this.screen.height); return this.onScreenVector; }); __publicField$11(this, "onCircleVector", new Vector2()); __publicField$11(this, "getMouseOnCircle", (pageX, pageY) => { this.onCircleVector.set((pageX - this.screen.width * .5 - this.screen.left) / (this.screen.width * .5), (this.screen.height + 2 * (this.screen.top - pageY)) / this.screen.width); return this.onCircleVector; }); __publicField$11(this, "axis", new Vector3()); __publicField$11(this, "quaternion", new Quaternion()); __publicField$11(this, "eyeDirection", new Vector3()); __publicField$11(this, "objectUpDirection", new Vector3()); __publicField$11(this, "objectSidewaysDirection", new Vector3()); __publicField$11(this, "moveDirection", new Vector3()); __publicField$11(this, "angle", 0); __publicField$11(this, "rotateCamera", () => { this.moveDirection.set(this._moveCurr.x - this._movePrev.x, this._moveCurr.y - this._movePrev.y, 0); this.angle = this.moveDirection.length(); if (this.angle) { this._eye.copy(this.object.position).sub(this.target); this.eyeDirection.copy(this._eye).normalize(); this.objectUpDirection.copy(this.object.up).normalize(); this.objectSidewaysDirection.crossVectors(this.objectUpDirection, this.eyeDirection).normalize(); this.objectUpDirection.setLength(this._moveCurr.y - this._movePrev.y); this.objectSidewaysDirection.setLength(this._moveCurr.x - this._movePrev.x); this.moveDirection.copy(this.objectUpDirection.add(this.objectSidewaysDirection)); this.axis.crossVectors(this.moveDirection, this._eye).normalize(); this.angle *= this.rotateSpeed; this.quaternion.setFromAxisAngle(this.axis, this.angle); this._eye.applyQuaternion(this.quaternion); this.object.up.applyQuaternion(this.quaternion); this._lastAxis.copy(this.axis); this._lastAngle = this.angle; } else if (!this.staticMoving && this._lastAngle) { this._lastAngle *= Math.sqrt(1 - this.dynamicDampingFactor); this._eye.copy(this.object.position).sub(this.target); this.quaternion.setFromAxisAngle(this._lastAxis, this._lastAngle); this._eye.applyQuaternion(this.quaternion); this.object.up.applyQuaternion(this.quaternion); } this._movePrev.copy(this._moveCurr); }); __publicField$11(this, "zoomCamera", () => { let factor; if (this._state === this.STATE.TOUCH_ZOOM_PAN) { factor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd; this._touchZoomDistanceStart = this._touchZoomDistanceEnd; if (this.object.isPerspectiveCamera) this._eye.multiplyScalar(factor); else if (this.object.isOrthographicCamera) { this.object.zoom /= factor; this.object.updateProjectionMatrix(); } else console.warn("THREE.TrackballControls: Unsupported camera type"); } else { factor = 1 + (this._zoomEnd.y - this._zoomStart.y) * this.zoomSpeed; if (Math.abs(factor - 1) > this.EPS && factor > 0) if (this.object.isPerspectiveCamera) { if (factor > 1 && this._eye.length() >= this.maxDistance - this.EPS) factor = 1; this._eye.multiplyScalar(factor); } else if (this.object.isOrthographicCamera) { if (factor > 1 && this.object.zoom < this.maxDistance * this.maxDistance) factor = 1; this.object.zoom /= factor; } else console.warn("THREE.TrackballControls: Unsupported camera type"); if (this.staticMoving) this._zoomStart.copy(this._zoomEnd); else this._zoomStart.y += (this._zoomEnd.y - this._zoomStart.y) * this.dynamicDampingFactor; if (this.cursorZoom) { this.targetVector.copy(this.target).project(this.object); let worldPos = this.cursorVector.set(this.mousePosition.x, this.mousePosition.y, this.targetVector.z).unproject(this.object); this.target.lerpVectors(worldPos, this.target, factor); } if (this.object.isOrthographicCamera) this.object.updateProjectionMatrix(); } }); __publicField$11(this, "mouseChange", new Vector2()); __publicField$11(this, "objectUp", new Vector3()); __publicField$11(this, "pan", new Vector3()); __publicField$11(this, "panCamera", () => { if (!this.domElement) return; this.mouseChange.copy(this._panEnd).sub(this._panStart); if (this.mouseChange.lengthSq() > this.EPS) { if (this.object.isOrthographicCamera) { const orthoObject = this.object; const scale_x = (orthoObject.right - orthoObject.left) / this.object.zoom; const scale_y = (orthoObject.top - orthoObject.bottom) / this.object.zoom; this.mouseChange.x *= scale_x; this.mouseChange.y *= scale_y; } else this.mouseChange.multiplyScalar(this._eye.length() * this.panSpeed); this.pan.copy(this._eye).cross(this.object.up).setLength(this.mouseChange.x); this.pan.add(this.objectUp.copy(this.object.up).setLength(this.mouseChange.y)); this.object.position.add(this.pan); this.target.add(this.pan); if (this.staticMoving) this._panStart.copy(this._panEnd); else this._panStart.add(this.mouseChange.subVectors(this._panEnd, this._panStart).multiplyScalar(this.dynamicDampingFactor)); } }); __publicField$11(this, "checkDistances", () => { if (!this.noZoom || !this.noPan) { if (this._eye.lengthSq() > this.maxDistance * this.maxDistance) { this.object.position.addVectors(this.target, this._eye.setLength(this.maxDistance)); this._zoomStart.copy(this._zoomEnd); } if (this._eye.lengthSq() < this.minDistance * this.minDistance) { this.object.position.addVectors(this.target, this._eye.setLength(this.minDistance)); this._zoomStart.copy(this._zoomEnd); } } }); __publicField$11(this, "handleResize", () => { if (!this.domElement) return; const box = this.domElement.getBoundingClientRect(); const d = this.domElement.ownerDocument.documentElement; this.screen.left = box.left + window.pageXOffset - d.clientLeft; this.screen.top = box.top + window.pageYOffset - d.clientTop; this.screen.width = box.width; this.screen.height = box.height; }); __publicField$11(this, "update", () => { this._eye.subVectors(this.object.position, this.target); if (!this.noRotate) this.rotateCamera(); if (!this.noZoom) this.zoomCamera(); if (!this.noPan) this.panCamera(); this.object.position.addVectors(this.target, this._eye); if (this.object.isPerspectiveCamera) { this.checkDistances(); this.object.lookAt(this.target); if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS) { this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); } } else if (this.object.isOrthographicCamera) { this.object.lookAt(this.target); if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || this.lastZoom !== this.object.zoom) { this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); this.lastZoom = this.object.zoom; } } else console.warn("THREE.TrackballControls: Unsupported camera type"); }); __publicField$11(this, "reset", () => { this._state = this.STATE.NONE; this._keyState = this.STATE.NONE; this.target.copy(this.target0); this.object.position.copy(this.position0); this.object.up.copy(this.up0); this.object.zoom = this.zoom0; this.object.updateProjectionMatrix(); this._eye.subVectors(this.object.position, this.target); this.object.lookAt(this.target); this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); this.lastZoom = this.object.zoom; }); __publicField$11(this, "keydown", (event) => { if (this.enabled === false) return; window.removeEventListener("keydown", this.keydown); if (this._keyState !== this.STATE.NONE) return; else if (event.code === this.keys[this.STATE.ROTATE] && !this.noRotate) this._keyState = this.STATE.ROTATE; else if (event.code === this.keys[this.STATE.ZOOM] && !this.noZoom) this._keyState = this.STATE.ZOOM; else if (event.code === this.keys[this.STATE.PAN] && !this.noPan) this._keyState = this.STATE.PAN; }); __publicField$11(this, "onPointerDown", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseDown(event); break; } }); __publicField$11(this, "onPointerMove", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseMove(event); break; } }); __publicField$11(this, "onPointerUp", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseUp(); break; } }); __publicField$11(this, "keyup", () => { if (this.enabled === false) return; this._keyState = this.STATE.NONE; window.addEventListener("keydown", this.keydown); }); __publicField$11(this, "onMouseDown", (event) => { if (!this.domElement) return; if (this._state === this.STATE.NONE) switch (event.button) { case this.mouseButtons.LEFT: this._state = this.STATE.ROTATE; break; case this.mouseButtons.MIDDLE: this._state = this.STATE.ZOOM; break; case this.mouseButtons.RIGHT: this._state = this.STATE.PAN; break; } const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state; if (state === this.STATE.ROTATE && !this.noRotate) { this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY)); this._movePrev.copy(this._moveCurr); } else if (state === this.STATE.ZOOM && !this.noZoom) { this._zoomStart.copy(this.getMouseOnScreen(event.pageX, event.pageY)); this._zoomEnd.copy(this._zoomStart); } else if (state === this.STATE.PAN && !this.noPan) { this._panStart.copy(this.getMouseOnScreen(event.pageX, event.pageY)); this._panEnd.copy(this._panStart); } this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp); this.dispatchEvent(this.startEvent); }); __publicField$11(this, "onMouseMove", (event) => { if (this.enabled === false) return; const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state; if (state === this.STATE.ROTATE && !this.noRotate) { this._movePrev.copy(this._moveCurr); this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY)); } else if (state === this.STATE.ZOOM && !this.noZoom) this._zoomEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY)); else if (state === this.STATE.PAN && !this.noPan) this._panEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY)); }); __publicField$11(this, "onMouseUp", () => { if (!this.domElement) return; if (this.enabled === false) return; this._state = this.STATE.NONE; this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp); this.dispatchEvent(this.endEvent); }); __publicField$11(this, "mousewheel", (event) => { if (this.enabled === false) return; if (this.noZoom === true) return; event.preventDefault(); switch (event.deltaMode) { case 2: this._zoomStart.y -= event.deltaY * .025; break; case 1: this._zoomStart.y -= event.deltaY * .01; break; default: this._zoomStart.y -= event.deltaY * 25e-5; break; } this.mousePosition.x = event.offsetX / this.screen.width * 2 - 1; this.mousePosition.y = -(event.offsetY / this.screen.height) * 2 + 1; this.dispatchEvent(this.startEvent); this.dispatchEvent(this.endEvent); }); __publicField$11(this, "touchstart", (event) => { if (this.enabled === false) return; event.preventDefault(); switch (event.touches.length) { case 1: this._state = this.STATE.TOUCH_ROTATE; this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); this._movePrev.copy(this._moveCurr); break; default: this._state = this.STATE.TOUCH_ZOOM_PAN; const dx = event.touches[0].pageX - event.touches[1].pageX; const dy = event.touches[0].pageY - event.touches[1].pageY; this._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy); const x = (event.touches[0].pageX + event.touches[1].pageX) / 2; const y = (event.touches[0].pageY + event.touches[1].pageY) / 2; this._panStart.copy(this.getMouseOnScreen(x, y)); this._panEnd.copy(this._panStart); break; } this.dispatchEvent(this.startEvent); }); __publicField$11(this, "touchmove", (event) => { if (this.enabled === false) return; event.preventDefault(); switch (event.touches.length) { case 1: this._movePrev.copy(this._moveCurr); this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); break; default: const dx = event.touches[0].pageX - event.touches[1].pageX; const dy = event.touches[0].pageY - event.touches[1].pageY; this._touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy); const x = (event.touches[0].pageX + event.touches[1].pageX) / 2; const y = (event.touches[0].pageY + event.touches[1].pageY) / 2; this._panEnd.copy(this.getMouseOnScreen(x, y)); break; } }); __publicField$11(this, "touchend", (event) => { if (this.enabled === false) return; switch (event.touches.length) { case 0: this._state = this.STATE.NONE; break; case 1: this._state = this.STATE.TOUCH_ROTATE; this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); this._movePrev.copy(this._moveCurr); break; } this.dispatchEvent(this.endEvent); }); __publicField$11(this, "contextmenu", (event) => { if (this.enabled === false) return; event.preventDefault(); }); __publicField$11(this, "connect", (domElement) => { if (domElement === document) console.error("THREE.OrbitControls: \"document\" should not be used as the target \"domElement\". Please use \"renderer.domElement\" instead."); this.domElement = domElement; this.domElement.addEventListener("contextmenu", this.contextmenu); this.domElement.addEventListener("pointerdown", this.onPointerDown); this.domElement.addEventListener("wheel", this.mousewheel); this.domElement.addEventListener("touchstart", this.touchstart); this.domElement.addEventListener("touchend", this.touchend); this.domElement.addEventListener("touchmove", this.touchmove); this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp); window.addEventListener("keydown", this.keydown); window.addEventListener("keyup", this.keyup); this.handleResize(); }); __publicField$11(this, "dispose", () => { if (!this.domElement) return; this.domElement.removeEventListener("contextmenu", this.contextmenu); this.domElement.removeEventListener("pointerdown", this.onPointerDown); this.domElement.removeEventListener("wheel", this.mousewheel); this.domElement.removeEventListener("touchstart", this.touchstart); this.domElement.removeEventListener("touchend", this.touchend); this.domElement.removeEventListener("touchmove", this.touchmove); this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp); window.removeEventListener("keydown", this.keydown); window.removeEventListener("keyup", this.keyup); }); this.object = object; this.target0 = this.target.clone(); this.position0 = this.object.position.clone(); this.up0 = this.object.up.clone(); this.zoom0 = this.object.zoom; if (domElement !== void 0) this.connect(domElement); this.update(); } }; //#endregion //#region node_modules/three-stdlib/controls/OrbitControls.js var __defProp$10 = Object.defineProperty; var __defNormalProp$10 = (obj, key, value) => key in obj ? __defProp$10(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$10 = (obj, key, value) => { __defNormalProp$10(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var _ray$3 = /* @__PURE__ */ new Ray(); var _plane = /* @__PURE__ */ new Plane$1(); var TILT_LIMIT = Math.cos(70 * (Math.PI / 180)); var moduloWrapAround = (offset, capacity) => (offset % capacity + capacity) % capacity; var OrbitControls$1 = class extends EventDispatcher$1 { constructor(object, domElement) { super(); __publicField$10(this, "object"); __publicField$10(this, "domElement"); __publicField$10(this, "enabled", true); __publicField$10(this, "target", new Vector3()); __publicField$10(this, "minDistance", 0); __publicField$10(this, "maxDistance", Infinity); __publicField$10(this, "minZoom", 0); __publicField$10(this, "maxZoom", Infinity); __publicField$10(this, "minPolarAngle", 0); __publicField$10(this, "maxPolarAngle", Math.PI); __publicField$10(this, "minAzimuthAngle", -Infinity); __publicField$10(this, "maxAzimuthAngle", Infinity); __publicField$10(this, "enableDamping", false); __publicField$10(this, "dampingFactor", .05); __publicField$10(this, "enableZoom", true); __publicField$10(this, "zoomSpeed", 1); __publicField$10(this, "enableRotate", true); __publicField$10(this, "rotateSpeed", 1); __publicField$10(this, "enablePan", true); __publicField$10(this, "panSpeed", 1); __publicField$10(this, "screenSpacePanning", true); __publicField$10(this, "keyPanSpeed", 7); __publicField$10(this, "zoomToCursor", false); __publicField$10(this, "autoRotate", false); __publicField$10(this, "autoRotateSpeed", 2); __publicField$10(this, "reverseOrbit", false); __publicField$10(this, "reverseHorizontalOrbit", false); __publicField$10(this, "reverseVerticalOrbit", false); __publicField$10(this, "keys", { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }); __publicField$10(this, "mouseButtons", { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }); __publicField$10(this, "touches", { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }); __publicField$10(this, "target0"); __publicField$10(this, "position0"); __publicField$10(this, "zoom0"); __publicField$10(this, "_domElementKeyEvents", null); __publicField$10(this, "getPolarAngle"); __publicField$10(this, "getAzimuthalAngle"); __publicField$10(this, "setPolarAngle"); __publicField$10(this, "setAzimuthalAngle"); __publicField$10(this, "getDistance"); __publicField$10(this, "getZoomScale"); __publicField$10(this, "listenToKeyEvents"); __publicField$10(this, "stopListenToKeyEvents"); __publicField$10(this, "saveState"); __publicField$10(this, "reset"); __publicField$10(this, "update"); __publicField$10(this, "connect"); __publicField$10(this, "dispose"); __publicField$10(this, "dollyIn"); __publicField$10(this, "dollyOut"); __publicField$10(this, "getScale"); __publicField$10(this, "setScale"); this.object = object; this.domElement = domElement; this.target0 = this.target.clone(); this.position0 = this.object.position.clone(); this.zoom0 = this.object.zoom; this.getPolarAngle = () => spherical.phi; this.getAzimuthalAngle = () => spherical.theta; this.setPolarAngle = (value) => { let phi = moduloWrapAround(value, 2 * Math.PI); let currentPhi = spherical.phi; if (currentPhi < 0) currentPhi += 2 * Math.PI; if (phi < 0) phi += 2 * Math.PI; let phiDist = Math.abs(phi - currentPhi); if (2 * Math.PI - phiDist < phiDist) if (phi < currentPhi) phi += 2 * Math.PI; else currentPhi += 2 * Math.PI; sphericalDelta.phi = phi - currentPhi; scope.update(); }; this.setAzimuthalAngle = (value) => { let theta = moduloWrapAround(value, 2 * Math.PI); let currentTheta = spherical.theta; if (currentTheta < 0) currentTheta += 2 * Math.PI; if (theta < 0) theta += 2 * Math.PI; let thetaDist = Math.abs(theta - currentTheta); if (2 * Math.PI - thetaDist < thetaDist) if (theta < currentTheta) theta += 2 * Math.PI; else currentTheta += 2 * Math.PI; sphericalDelta.theta = theta - currentTheta; scope.update(); }; this.getDistance = () => scope.object.position.distanceTo(scope.target); this.listenToKeyEvents = (domElement2) => { domElement2.addEventListener("keydown", onKeyDown); this._domElementKeyEvents = domElement2; }; this.stopListenToKeyEvents = () => { this._domElementKeyEvents.removeEventListener("keydown", onKeyDown); this._domElementKeyEvents = null; }; this.saveState = () => { scope.target0.copy(scope.target); scope.position0.copy(scope.object.position); scope.zoom0 = scope.object.zoom; }; this.reset = () => { scope.target.copy(scope.target0); scope.object.position.copy(scope.position0); scope.object.zoom = scope.zoom0; scope.object.updateProjectionMatrix(); scope.dispatchEvent(changeEvent); scope.update(); state = STATE.NONE; }; this.update = (() => { const offset = new Vector3(); const up = new Vector3(0, 1, 0); const quat = new Quaternion().setFromUnitVectors(object.up, up); const quatInverse = quat.clone().invert(); const lastPosition = new Vector3(); const lastQuaternion = new Quaternion(); const twoPI = 2 * Math.PI; return function update() { const position = scope.object.position; quat.setFromUnitVectors(object.up, up); quatInverse.copy(quat).invert(); offset.copy(position).sub(scope.target); offset.applyQuaternion(quat); spherical.setFromVector3(offset); if (scope.autoRotate && state === STATE.NONE) rotateLeft(getAutoRotationAngle()); if (scope.enableDamping) { spherical.theta += sphericalDelta.theta * scope.dampingFactor; spherical.phi += sphericalDelta.phi * scope.dampingFactor; } else { spherical.theta += sphericalDelta.theta; spherical.phi += sphericalDelta.phi; } let min = scope.minAzimuthAngle; let max = scope.maxAzimuthAngle; if (isFinite(min) && isFinite(max)) { if (min < -Math.PI) min += twoPI; else if (min > Math.PI) min -= twoPI; if (max < -Math.PI) max += twoPI; else if (max > Math.PI) max -= twoPI; if (min <= max) spherical.theta = Math.max(min, Math.min(max, spherical.theta)); else spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta); } spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi)); spherical.makeSafe(); if (scope.enableDamping === true) scope.target.addScaledVector(panOffset, scope.dampingFactor); else scope.target.add(panOffset); if (scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera) spherical.radius = clampDistance(spherical.radius); else spherical.radius = clampDistance(spherical.radius * scale); offset.setFromSpherical(spherical); offset.applyQuaternion(quatInverse); position.copy(scope.target).add(offset); if (!scope.object.matrixAutoUpdate) scope.object.updateMatrix(); scope.object.lookAt(scope.target); if (scope.enableDamping === true) { sphericalDelta.theta *= 1 - scope.dampingFactor; sphericalDelta.phi *= 1 - scope.dampingFactor; panOffset.multiplyScalar(1 - scope.dampingFactor); } else { sphericalDelta.set(0, 0, 0); panOffset.set(0, 0, 0); } let zoomChanged = false; if (scope.zoomToCursor && performCursorZoom) { let newRadius = null; if (scope.object instanceof PerspectiveCamera$1 && scope.object.isPerspectiveCamera) { const prevRadius = offset.length(); newRadius = clampDistance(prevRadius * scale); const radiusDelta = prevRadius - newRadius; scope.object.position.addScaledVector(dollyDirection, radiusDelta); scope.object.updateMatrixWorld(); } else if (scope.object.isOrthographicCamera) { const mouseBefore = new Vector3(mouse.x, mouse.y, 0); mouseBefore.unproject(scope.object); scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale)); scope.object.updateProjectionMatrix(); zoomChanged = true; const mouseAfter = new Vector3(mouse.x, mouse.y, 0); mouseAfter.unproject(scope.object); scope.object.position.sub(mouseAfter).add(mouseBefore); scope.object.updateMatrixWorld(); newRadius = offset.length(); } else { console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."); scope.zoomToCursor = false; } if (newRadius !== null) if (scope.screenSpacePanning) scope.target.set(0, 0, -1).transformDirection(scope.object.matrix).multiplyScalar(newRadius).add(scope.object.position); else { _ray$3.origin.copy(scope.object.position); _ray$3.direction.set(0, 0, -1).transformDirection(scope.object.matrix); if (Math.abs(scope.object.up.dot(_ray$3.direction)) < TILT_LIMIT) object.lookAt(scope.target); else { _plane.setFromNormalAndCoplanarPoint(scope.object.up, scope.target); _ray$3.intersectPlane(_plane, scope.target); } } } else if (scope.object instanceof OrthographicCamera$1 && scope.object.isOrthographicCamera) { zoomChanged = scale !== 1; if (zoomChanged) { scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale)); scope.object.updateProjectionMatrix(); } } scale = 1; performCursorZoom = false; if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) { scope.dispatchEvent(changeEvent); lastPosition.copy(scope.object.position); lastQuaternion.copy(scope.object.quaternion); zoomChanged = false; return true; } return false; }; })(); this.connect = (domElement2) => { scope.domElement = domElement2; scope.domElement.style.touchAction = "none"; scope.domElement.addEventListener("contextmenu", onContextMenu); scope.domElement.addEventListener("pointerdown", onPointerDown); scope.domElement.addEventListener("pointercancel", onPointerUp); scope.domElement.addEventListener("wheel", onMouseWheel); }; this.dispose = () => { var _a, _b, _c, _d, _e, _f; if (scope.domElement) scope.domElement.style.touchAction = "auto"; (_a = scope.domElement) == null || _a.removeEventListener("contextmenu", onContextMenu); (_b = scope.domElement) == null || _b.removeEventListener("pointerdown", onPointerDown); (_c = scope.domElement) == null || _c.removeEventListener("pointercancel", onPointerUp); (_d = scope.domElement) == null || _d.removeEventListener("wheel", onMouseWheel); (_e = scope.domElement) == null || _e.ownerDocument.removeEventListener("pointermove", onPointerMove); (_f = scope.domElement) == null || _f.ownerDocument.removeEventListener("pointerup", onPointerUp); if (scope._domElementKeyEvents !== null) scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown); }; const scope = this; const changeEvent = { type: "change" }; const startEvent = { type: "start" }; const endEvent = { type: "end" }; const STATE = { NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_PAN: 4, TOUCH_DOLLY_PAN: 5, TOUCH_DOLLY_ROTATE: 6 }; let state = STATE.NONE; const EPS = 1e-6; const spherical = new Spherical(); const sphericalDelta = new Spherical(); let scale = 1; const panOffset = new Vector3(); const rotateStart = new Vector2(); const rotateEnd = new Vector2(); const rotateDelta = new Vector2(); const panStart = new Vector2(); const panEnd = new Vector2(); const panDelta = new Vector2(); const dollyStart = new Vector2(); const dollyEnd = new Vector2(); const dollyDelta = new Vector2(); const dollyDirection = new Vector3(); const mouse = new Vector2(); let performCursorZoom = false; const pointers = []; const pointerPositions = {}; function getAutoRotationAngle() { return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; } function getZoomScale() { return Math.pow(.95, scope.zoomSpeed); } function rotateLeft(angle) { if (scope.reverseOrbit || scope.reverseHorizontalOrbit) sphericalDelta.theta += angle; else sphericalDelta.theta -= angle; } function rotateUp(angle) { if (scope.reverseOrbit || scope.reverseVerticalOrbit) sphericalDelta.phi += angle; else sphericalDelta.phi -= angle; } const panLeft = (() => { const v = new Vector3(); return function panLeft2(distance, objectMatrix) { v.setFromMatrixColumn(objectMatrix, 0); v.multiplyScalar(-distance); panOffset.add(v); }; })(); const panUp = (() => { const v = new Vector3(); return function panUp2(distance, objectMatrix) { if (scope.screenSpacePanning === true) v.setFromMatrixColumn(objectMatrix, 1); else { v.setFromMatrixColumn(objectMatrix, 0); v.crossVectors(scope.object.up, v); } v.multiplyScalar(distance); panOffset.add(v); }; })(); const pan = (() => { const offset = new Vector3(); return function pan2(deltaX, deltaY) { const element = scope.domElement; if (element && scope.object instanceof PerspectiveCamera$1 && scope.object.isPerspectiveCamera) { const position = scope.object.position; offset.copy(position).sub(scope.target); let targetDistance = offset.length(); targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180); panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix); panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix); } else if (element && scope.object instanceof OrthographicCamera$1 && scope.object.isOrthographicCamera) { panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix); panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix); } else { console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."); scope.enablePan = false; } }; })(); function setScale(newScale) { if (scope.object instanceof PerspectiveCamera$1 && scope.object.isPerspectiveCamera || scope.object instanceof OrthographicCamera$1 && scope.object.isOrthographicCamera) scale = newScale; else { console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."); scope.enableZoom = false; } } function dollyOut(dollyScale) { setScale(scale / dollyScale); } function dollyIn(dollyScale) { setScale(scale * dollyScale); } function updateMouseParameters(event) { if (!scope.zoomToCursor || !scope.domElement) return; performCursorZoom = true; const rect = scope.domElement.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const w = rect.width; const h = rect.height; mouse.x = x / w * 2 - 1; mouse.y = -(y / h) * 2 + 1; dollyDirection.set(mouse.x, mouse.y, 1).unproject(scope.object).sub(scope.object.position).normalize(); } function clampDistance(dist) { return Math.max(scope.minDistance, Math.min(scope.maxDistance, dist)); } function handleMouseDownRotate(event) { rotateStart.set(event.clientX, event.clientY); } function handleMouseDownDolly(event) { updateMouseParameters(event); dollyStart.set(event.clientX, event.clientY); } function handleMouseDownPan(event) { panStart.set(event.clientX, event.clientY); } function handleMouseMoveRotate(event) { rotateEnd.set(event.clientX, event.clientY); rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); const element = scope.domElement; if (element) { rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); } rotateStart.copy(rotateEnd); scope.update(); } function handleMouseMoveDolly(event) { dollyEnd.set(event.clientX, event.clientY); dollyDelta.subVectors(dollyEnd, dollyStart); if (dollyDelta.y > 0) dollyOut(getZoomScale()); else if (dollyDelta.y < 0) dollyIn(getZoomScale()); dollyStart.copy(dollyEnd); scope.update(); } function handleMouseMovePan(event) { panEnd.set(event.clientX, event.clientY); panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); pan(panDelta.x, panDelta.y); panStart.copy(panEnd); scope.update(); } function handleMouseWheel(event) { updateMouseParameters(event); if (event.deltaY < 0) dollyIn(getZoomScale()); else if (event.deltaY > 0) dollyOut(getZoomScale()); scope.update(); } function handleKeyDown(event) { let needsUpdate = false; switch (event.code) { case scope.keys.UP: pan(0, scope.keyPanSpeed); needsUpdate = true; break; case scope.keys.BOTTOM: pan(0, -scope.keyPanSpeed); needsUpdate = true; break; case scope.keys.LEFT: pan(scope.keyPanSpeed, 0); needsUpdate = true; break; case scope.keys.RIGHT: pan(-scope.keyPanSpeed, 0); needsUpdate = true; break; } if (needsUpdate) { event.preventDefault(); scope.update(); } } function handleTouchStartRotate() { if (pointers.length == 1) rotateStart.set(pointers[0].pageX, pointers[0].pageY); else { const x = .5 * (pointers[0].pageX + pointers[1].pageX); const y = .5 * (pointers[0].pageY + pointers[1].pageY); rotateStart.set(x, y); } } function handleTouchStartPan() { if (pointers.length == 1) panStart.set(pointers[0].pageX, pointers[0].pageY); else { const x = .5 * (pointers[0].pageX + pointers[1].pageX); const y = .5 * (pointers[0].pageY + pointers[1].pageY); panStart.set(x, y); } } function handleTouchStartDolly() { const dx = pointers[0].pageX - pointers[1].pageX; const dy = pointers[0].pageY - pointers[1].pageY; const distance = Math.sqrt(dx * dx + dy * dy); dollyStart.set(0, distance); } function handleTouchStartDollyPan() { if (scope.enableZoom) handleTouchStartDolly(); if (scope.enablePan) handleTouchStartPan(); } function handleTouchStartDollyRotate() { if (scope.enableZoom) handleTouchStartDolly(); if (scope.enableRotate) handleTouchStartRotate(); } function handleTouchMoveRotate(event) { if (pointers.length == 1) rotateEnd.set(event.pageX, event.pageY); else { const position = getSecondPointerPosition(event); const x = .5 * (event.pageX + position.x); const y = .5 * (event.pageY + position.y); rotateEnd.set(x, y); } rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); const element = scope.domElement; if (element) { rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); } rotateStart.copy(rotateEnd); } function handleTouchMovePan(event) { if (pointers.length == 1) panEnd.set(event.pageX, event.pageY); else { const position = getSecondPointerPosition(event); const x = .5 * (event.pageX + position.x); const y = .5 * (event.pageY + position.y); panEnd.set(x, y); } panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); pan(panDelta.x, panDelta.y); panStart.copy(panEnd); } function handleTouchMoveDolly(event) { const position = getSecondPointerPosition(event); const dx = event.pageX - position.x; const dy = event.pageY - position.y; const distance = Math.sqrt(dx * dx + dy * dy); dollyEnd.set(0, distance); dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed)); dollyOut(dollyDelta.y); dollyStart.copy(dollyEnd); } function handleTouchMoveDollyPan(event) { if (scope.enableZoom) handleTouchMoveDolly(event); if (scope.enablePan) handleTouchMovePan(event); } function handleTouchMoveDollyRotate(event) { if (scope.enableZoom) handleTouchMoveDolly(event); if (scope.enableRotate) handleTouchMoveRotate(event); } function onPointerDown(event) { var _a, _b; if (scope.enabled === false) return; if (pointers.length === 0) { (_a = scope.domElement) == null || _a.ownerDocument.addEventListener("pointermove", onPointerMove); (_b = scope.domElement) == null || _b.ownerDocument.addEventListener("pointerup", onPointerUp); } addPointer(event); if (event.pointerType === "touch") onTouchStart(event); else onMouseDown(event); } function onPointerMove(event) { if (scope.enabled === false) return; if (event.pointerType === "touch") onTouchMove(event); else onMouseMove(event); } function onPointerUp(event) { var _a, _b, _c; removePointer(event); if (pointers.length === 0) { (_a = scope.domElement) == null || _a.releasePointerCapture(event.pointerId); (_b = scope.domElement) == null || _b.ownerDocument.removeEventListener("pointermove", onPointerMove); (_c = scope.domElement) == null || _c.ownerDocument.removeEventListener("pointerup", onPointerUp); } scope.dispatchEvent(endEvent); state = STATE.NONE; } function onMouseDown(event) { let mouseAction; switch (event.button) { case 0: mouseAction = scope.mouseButtons.LEFT; break; case 1: mouseAction = scope.mouseButtons.MIDDLE; break; case 2: mouseAction = scope.mouseButtons.RIGHT; break; default: mouseAction = -1; } switch (mouseAction) { case MOUSE.DOLLY: if (scope.enableZoom === false) return; handleMouseDownDolly(event); state = STATE.DOLLY; break; case MOUSE.ROTATE: if (event.ctrlKey || event.metaKey || event.shiftKey) { if (scope.enablePan === false) return; handleMouseDownPan(event); state = STATE.PAN; } else { if (scope.enableRotate === false) return; handleMouseDownRotate(event); state = STATE.ROTATE; } break; case MOUSE.PAN: if (event.ctrlKey || event.metaKey || event.shiftKey) { if (scope.enableRotate === false) return; handleMouseDownRotate(event); state = STATE.ROTATE; } else { if (scope.enablePan === false) return; handleMouseDownPan(event); state = STATE.PAN; } break; default: state = STATE.NONE; } if (state !== STATE.NONE) scope.dispatchEvent(startEvent); } function onMouseMove(event) { if (scope.enabled === false) return; switch (state) { case STATE.ROTATE: if (scope.enableRotate === false) return; handleMouseMoveRotate(event); break; case STATE.DOLLY: if (scope.enableZoom === false) return; handleMouseMoveDolly(event); break; case STATE.PAN: if (scope.enablePan === false) return; handleMouseMovePan(event); break; } } function onMouseWheel(event) { if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE) return; event.preventDefault(); scope.dispatchEvent(startEvent); handleMouseWheel(event); scope.dispatchEvent(endEvent); } function onKeyDown(event) { if (scope.enabled === false || scope.enablePan === false) return; handleKeyDown(event); } function onTouchStart(event) { trackPointer(event); switch (pointers.length) { case 1: switch (scope.touches.ONE) { case TOUCH.ROTATE: if (scope.enableRotate === false) return; handleTouchStartRotate(); state = STATE.TOUCH_ROTATE; break; case TOUCH.PAN: if (scope.enablePan === false) return; handleTouchStartPan(); state = STATE.TOUCH_PAN; break; default: state = STATE.NONE; } break; case 2: switch (scope.touches.TWO) { case TOUCH.DOLLY_PAN: if (scope.enableZoom === false && scope.enablePan === false) return; handleTouchStartDollyPan(); state = STATE.TOUCH_DOLLY_PAN; break; case TOUCH.DOLLY_ROTATE: if (scope.enableZoom === false && scope.enableRotate === false) return; handleTouchStartDollyRotate(); state = STATE.TOUCH_DOLLY_ROTATE; break; default: state = STATE.NONE; } break; default: state = STATE.NONE; } if (state !== STATE.NONE) scope.dispatchEvent(startEvent); } function onTouchMove(event) { trackPointer(event); switch (state) { case STATE.TOUCH_ROTATE: if (scope.enableRotate === false) return; handleTouchMoveRotate(event); scope.update(); break; case STATE.TOUCH_PAN: if (scope.enablePan === false) return; handleTouchMovePan(event); scope.update(); break; case STATE.TOUCH_DOLLY_PAN: if (scope.enableZoom === false && scope.enablePan === false) return; handleTouchMoveDollyPan(event); scope.update(); break; case STATE.TOUCH_DOLLY_ROTATE: if (scope.enableZoom === false && scope.enableRotate === false) return; handleTouchMoveDollyRotate(event); scope.update(); break; default: state = STATE.NONE; } } function onContextMenu(event) { if (scope.enabled === false) return; event.preventDefault(); } function addPointer(event) { pointers.push(event); } function removePointer(event) { delete pointerPositions[event.pointerId]; for (let i = 0; i < pointers.length; i++) if (pointers[i].pointerId == event.pointerId) { pointers.splice(i, 1); return; } } function trackPointer(event) { let position = pointerPositions[event.pointerId]; if (position === void 0) { position = new Vector2(); pointerPositions[event.pointerId] = position; } position.set(event.pageX, event.pageY); } function getSecondPointerPosition(event) { return pointerPositions[(event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0]).pointerId]; } this.dollyIn = (dollyScale = getZoomScale()) => { dollyIn(dollyScale); scope.update(); }; this.dollyOut = (dollyScale = getZoomScale()) => { dollyOut(dollyScale); scope.update(); }; this.getScale = () => { return scale; }; this.setScale = (newScale) => { setScale(newScale); scope.update(); }; this.getZoomScale = () => { return getZoomScale(); }; if (domElement !== void 0) this.connect(domElement); this.update(); } }; var MapControls$1 = class extends OrbitControls$1 { constructor(object, domElement) { super(object, domElement); this.screenSpacePanning = false; this.mouseButtons.LEFT = MOUSE.PAN; this.mouseButtons.RIGHT = MOUSE.ROTATE; this.touches.ONE = TOUCH.PAN; this.touches.TWO = TOUCH.DOLLY_ROTATE; } }; //#endregion //#region node_modules/three-stdlib/controls/ArcballControls.js var __defProp$9 = Object.defineProperty; var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$9 = (obj, key, value) => { __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var STATE = { IDLE: Symbol(), ROTATE: Symbol(), PAN: Symbol(), SCALE: Symbol(), FOV: Symbol(), FOCUS: Symbol(), ZROTATE: Symbol(), TOUCH_MULTI: Symbol(), ANIMATION_FOCUS: Symbol(), ANIMATION_ROTATE: Symbol() }; var INPUT = { NONE: Symbol(), ONE_FINGER: Symbol(), ONE_FINGER_SWITCHED: Symbol(), TWO_FINGER: Symbol(), MULT_FINGER: Symbol(), CURSOR: Symbol() }; var _center = { x: 0, y: 0 }; var _transformation = { camera: /* @__PURE__ */ new Matrix4(), gizmos: /* @__PURE__ */ new Matrix4() }; var _changeEvent = { type: "change" }; var _startEvent = { type: "start" }; var _endEvent = { type: "end" }; var ArcballControls$1 = class extends EventDispatcher$1 { constructor(camera, domElement = null, scene = null) { super(); __publicField$9(this, "camera"); __publicField$9(this, "domElement"); __publicField$9(this, "scene"); __publicField$9(this, "mouseActions"); __publicField$9(this, "_mouseOp"); __publicField$9(this, "_v2_1"); __publicField$9(this, "_v3_1"); __publicField$9(this, "_v3_2"); __publicField$9(this, "_m4_1"); __publicField$9(this, "_m4_2"); __publicField$9(this, "_quat"); __publicField$9(this, "_translationMatrix"); __publicField$9(this, "_rotationMatrix"); __publicField$9(this, "_scaleMatrix"); __publicField$9(this, "_rotationAxis"); __publicField$9(this, "_cameraMatrixState"); __publicField$9(this, "_cameraProjectionState"); __publicField$9(this, "_fovState"); __publicField$9(this, "_upState"); __publicField$9(this, "_zoomState"); __publicField$9(this, "_nearPos"); __publicField$9(this, "_farPos"); __publicField$9(this, "_gizmoMatrixState"); __publicField$9(this, "_up0"); __publicField$9(this, "_zoom0"); __publicField$9(this, "_fov0"); __publicField$9(this, "_initialNear"); __publicField$9(this, "_nearPos0"); __publicField$9(this, "_initialFar"); __publicField$9(this, "_farPos0"); __publicField$9(this, "_cameraMatrixState0"); __publicField$9(this, "_gizmoMatrixState0"); __publicField$9(this, "_button"); __publicField$9(this, "_touchStart"); __publicField$9(this, "_touchCurrent"); __publicField$9(this, "_input"); __publicField$9(this, "_switchSensibility"); __publicField$9(this, "_startFingerDistance"); __publicField$9(this, "_currentFingerDistance"); __publicField$9(this, "_startFingerRotation"); __publicField$9(this, "_currentFingerRotation"); __publicField$9(this, "_devPxRatio"); __publicField$9(this, "_downValid"); __publicField$9(this, "_nclicks"); __publicField$9(this, "_downEvents"); __publicField$9(this, "_clickStart"); __publicField$9(this, "_maxDownTime"); __publicField$9(this, "_maxInterval"); __publicField$9(this, "_posThreshold"); __publicField$9(this, "_movementThreshold"); __publicField$9(this, "_currentCursorPosition"); __publicField$9(this, "_startCursorPosition"); __publicField$9(this, "_grid"); __publicField$9(this, "_gridPosition"); __publicField$9(this, "_gizmos"); __publicField$9(this, "_curvePts"); __publicField$9(this, "_timeStart"); __publicField$9(this, "_animationId"); __publicField$9(this, "focusAnimationTime"); __publicField$9(this, "_timePrev"); __publicField$9(this, "_timeCurrent"); __publicField$9(this, "_anglePrev"); __publicField$9(this, "_angleCurrent"); __publicField$9(this, "_cursorPosPrev"); __publicField$9(this, "_cursorPosCurr"); __publicField$9(this, "_wPrev"); __publicField$9(this, "_wCurr"); __publicField$9(this, "adjustNearFar"); __publicField$9(this, "scaleFactor"); __publicField$9(this, "dampingFactor"); __publicField$9(this, "wMax"); __publicField$9(this, "enableAnimations"); __publicField$9(this, "enableGrid"); __publicField$9(this, "cursorZoom"); __publicField$9(this, "minFov"); __publicField$9(this, "maxFov"); __publicField$9(this, "enabled"); __publicField$9(this, "enablePan"); __publicField$9(this, "enableRotate"); __publicField$9(this, "enableZoom"); __publicField$9(this, "minDistance"); __publicField$9(this, "maxDistance"); __publicField$9(this, "minZoom"); __publicField$9(this, "maxZoom"); __publicField$9(this, "target"); __publicField$9(this, "_currentTarget"); __publicField$9(this, "_tbRadius"); __publicField$9(this, "_state"); __publicField$9(this, "onWindowResize", () => { const scale = (this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z) / 3; if (this.camera) { const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; } const newRadius = this._tbRadius / scale; const points = new EllipseCurve(0, 0, newRadius, newRadius).getPoints(this._curvePts); const curveGeometry = new BufferGeometry().setFromPoints(points); for (const gizmo in this._gizmos.children) { const child = this._gizmos.children[gizmo]; child.geometry = curveGeometry; } this.dispatchEvent(_changeEvent); }); __publicField$9(this, "onContextMenu", (event) => { if (!this.enabled) return; for (let i = 0; i < this.mouseActions.length; i++) if (this.mouseActions[i].mouse == 2) { event.preventDefault(); break; } }); __publicField$9(this, "onPointerCancel", () => { this._touchStart.splice(0, this._touchStart.length); this._touchCurrent.splice(0, this._touchCurrent.length); this._input = INPUT.NONE; }); __publicField$9(this, "onPointerDown", (event) => { if (event.button == 0 && event.isPrimary) { this._downValid = true; this._downEvents.push(event); } else this._downValid = false; if (event.pointerType == "touch" && this._input != INPUT.CURSOR) { this._touchStart.push(event); this._touchCurrent.push(event); switch (this._input) { case INPUT.NONE: this._input = INPUT.ONE_FINGER; this.onSinglePanStart(event, "ROTATE"); window.addEventListener("pointermove", this.onPointerMove); window.addEventListener("pointerup", this.onPointerUp); break; case INPUT.ONE_FINGER: case INPUT.ONE_FINGER_SWITCHED: this._input = INPUT.TWO_FINGER; this.onRotateStart(); this.onPinchStart(); this.onDoublePanStart(); break; case INPUT.TWO_FINGER: this._input = INPUT.MULT_FINGER; this.onTriplePanStart(); break; } } else if (event.pointerType != "touch" && this._input == INPUT.NONE) { let modifier = null; if (event.ctrlKey || event.metaKey) modifier = "CTRL"; else if (event.shiftKey) modifier = "SHIFT"; this._mouseOp = this.getOpFromAction(event.button, modifier); if (this._mouseOp) { window.addEventListener("pointermove", this.onPointerMove); window.addEventListener("pointerup", this.onPointerUp); this._input = INPUT.CURSOR; this._button = event.button; this.onSinglePanStart(event, this._mouseOp); } } }); __publicField$9(this, "onPointerMove", (event) => { if (event.pointerType == "touch" && this._input != INPUT.CURSOR) switch (this._input) { case INPUT.ONE_FINGER: this.updateTouchEvent(event); this.onSinglePanMove(event, STATE.ROTATE); break; case INPUT.ONE_FINGER_SWITCHED: if (this.calculatePointersDistance(this._touchCurrent[0], event) * this._devPxRatio >= this._switchSensibility) { this._input = INPUT.ONE_FINGER; this.updateTouchEvent(event); this.onSinglePanStart(event, "ROTATE"); break; } break; case INPUT.TWO_FINGER: this.updateTouchEvent(event); this.onRotateMove(); this.onPinchMove(); this.onDoublePanMove(); break; case INPUT.MULT_FINGER: this.updateTouchEvent(event); this.onTriplePanMove(); break; } else if (event.pointerType != "touch" && this._input == INPUT.CURSOR) { let modifier = null; if (event.ctrlKey || event.metaKey) modifier = "CTRL"; else if (event.shiftKey) modifier = "SHIFT"; const mouseOpState = this.getOpStateFromAction(this._button, modifier); if (mouseOpState) this.onSinglePanMove(event, mouseOpState); } if (this._downValid) { if (this.calculatePointersDistance(this._downEvents[this._downEvents.length - 1], event) * this._devPxRatio > this._movementThreshold) this._downValid = false; } }); __publicField$9(this, "onPointerUp", (event) => { if (event.pointerType == "touch" && this._input != INPUT.CURSOR) { const nTouch = this._touchCurrent.length; for (let i = 0; i < nTouch; i++) if (this._touchCurrent[i].pointerId == event.pointerId) { this._touchCurrent.splice(i, 1); this._touchStart.splice(i, 1); break; } switch (this._input) { case INPUT.ONE_FINGER: case INPUT.ONE_FINGER_SWITCHED: window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); this._input = INPUT.NONE; this.onSinglePanEnd(); break; case INPUT.TWO_FINGER: this.onDoublePanEnd(); this.onPinchEnd(); this.onRotateEnd(); this._input = INPUT.ONE_FINGER_SWITCHED; break; case INPUT.MULT_FINGER: if (this._touchCurrent.length == 0) { window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); this._input = INPUT.NONE; this.onTriplePanEnd(); } break; } } else if (event.pointerType != "touch" && this._input == INPUT.CURSOR) { window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); this._input = INPUT.NONE; this.onSinglePanEnd(); this._button = -1; } if (event.isPrimary) if (this._downValid) if (event.timeStamp - this._downEvents[this._downEvents.length - 1].timeStamp <= this._maxDownTime) if (this._nclicks == 0) { this._nclicks = 1; this._clickStart = performance.now(); } else { const clickInterval = event.timeStamp - this._clickStart; const movement = this.calculatePointersDistance(this._downEvents[1], this._downEvents[0]) * this._devPxRatio; if (clickInterval <= this._maxInterval && movement <= this._posThreshold) { this._nclicks = 0; this._downEvents.splice(0, this._downEvents.length); this.onDoubleTap(event); } else { this._nclicks = 1; this._downEvents.shift(); this._clickStart = performance.now(); } } else { this._downValid = false; this._nclicks = 0; this._downEvents.splice(0, this._downEvents.length); } else { this._nclicks = 0; this._downEvents.splice(0, this._downEvents.length); } }); __publicField$9(this, "onWheel", (event) => { var _a, _b; if (this.enabled && this.enableZoom && this.domElement) { let modifier = null; if (event.ctrlKey || event.metaKey) modifier = "CTRL"; else if (event.shiftKey) modifier = "SHIFT"; const mouseOp = this.getOpFromAction("WHEEL", modifier); if (mouseOp) { event.preventDefault(); this.dispatchEvent(_startEvent); const notchDeltaY = 125; let sgn = event.deltaY / notchDeltaY; let size = 1; if (sgn > 0) size = 1 / this.scaleFactor; else if (sgn < 0) size = this.scaleFactor; switch (mouseOp) { case "ZOOM": this.updateTbState(STATE.SCALE, true); if (sgn > 0) size = 1 / Math.pow(this.scaleFactor, sgn); else if (sgn < 0) size = Math.pow(this.scaleFactor, -sgn); if (this.cursorZoom && this.enablePan) { let scalePoint; if (this.camera instanceof OrthographicCamera$1) scalePoint = (_a = this.unprojectOnTbPlane(this.camera, event.clientX, event.clientY, this.domElement)) == null ? void 0 : _a.applyQuaternion(this.camera.quaternion).multiplyScalar(1 / this.camera.zoom).add(this._gizmos.position); if (this.camera instanceof PerspectiveCamera$1) scalePoint = (_b = this.unprojectOnTbPlane(this.camera, event.clientX, event.clientY, this.domElement)) == null ? void 0 : _b.applyQuaternion(this.camera.quaternion).add(this._gizmos.position); if (scalePoint !== void 0) this.applyTransformMatrix(this.applyScale(size, scalePoint)); } else this.applyTransformMatrix(this.applyScale(size, this._gizmos.position)); if (this._grid) { this.disposeGrid(); this.drawGrid(); } this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_changeEvent); this.dispatchEvent(_endEvent); break; case "FOV": if (this.camera instanceof PerspectiveCamera$1) { this.updateTbState(STATE.FOV, true); if (event.deltaX != 0) { sgn = event.deltaX / notchDeltaY; size = 1; if (sgn > 0) size = 1 / Math.pow(this.scaleFactor, sgn); else if (sgn < 0) size = Math.pow(this.scaleFactor, -sgn); } this._v3_1.setFromMatrixPosition(this._cameraMatrixState); const x = this._v3_1.distanceTo(this._gizmos.position); let xNew = x / size; xNew = MathUtils.clamp(xNew, this.minDistance, this.maxDistance); const y = x * Math.tan(MathUtils.DEG2RAD * this.camera.fov * .5); let newFov = MathUtils.RAD2DEG * (Math.atan(y / xNew) * 2); if (newFov > this.maxFov) newFov = this.maxFov; else if (newFov < this.minFov) newFov = this.minFov; size = x / (y / Math.tan(MathUtils.DEG2RAD * (newFov / 2))); this.setFov(newFov); this.applyTransformMatrix(this.applyScale(size, this._gizmos.position, false)); } if (this._grid) { this.disposeGrid(); this.drawGrid(); } this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_changeEvent); this.dispatchEvent(_endEvent); break; } } } }); __publicField$9(this, "onSinglePanStart", (event, operation) => { if (this.enabled && this.domElement) { this.dispatchEvent(_startEvent); this.setCenter(event.clientX, event.clientY); switch (operation) { case "PAN": if (!this.enablePan) return; if (this._animationId != -1) { cancelAnimationFrame(this._animationId); this._animationId = -1; this._timeStart = -1; this.activateGizmos(false); this.dispatchEvent(_changeEvent); } if (this.camera) { this.updateTbState(STATE.PAN, true); const rayDir = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement); if (rayDir !== void 0) this._startCursorPosition.copy(rayDir); if (this.enableGrid) { this.drawGrid(); this.dispatchEvent(_changeEvent); } } break; case "ROTATE": if (!this.enableRotate) return; if (this._animationId != -1) { cancelAnimationFrame(this._animationId); this._animationId = -1; this._timeStart = -1; } if (this.camera) { this.updateTbState(STATE.ROTATE, true); const rayDir = this.unprojectOnTbSurface(this.camera, _center.x, _center.y, this.domElement, this._tbRadius); if (rayDir !== void 0) this._startCursorPosition.copy(rayDir); this.activateGizmos(true); if (this.enableAnimations) { this._timePrev = this._timeCurrent = performance.now(); this._angleCurrent = this._anglePrev = 0; this._cursorPosPrev.copy(this._startCursorPosition); this._cursorPosCurr.copy(this._cursorPosPrev); this._wCurr = 0; this._wPrev = this._wCurr; } } this.dispatchEvent(_changeEvent); break; case "FOV": if (!this.enableZoom) return; if (this.camera instanceof PerspectiveCamera$1) { if (this._animationId != -1) { cancelAnimationFrame(this._animationId); this._animationId = -1; this._timeStart = -1; this.activateGizmos(false); this.dispatchEvent(_changeEvent); } this.updateTbState(STATE.FOV, true); this._startCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); this._currentCursorPosition.copy(this._startCursorPosition); } break; case "ZOOM": if (!this.enableZoom) return; if (this._animationId != -1) { cancelAnimationFrame(this._animationId); this._animationId = -1; this._timeStart = -1; this.activateGizmos(false); this.dispatchEvent(_changeEvent); } this.updateTbState(STATE.SCALE, true); this._startCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); this._currentCursorPosition.copy(this._startCursorPosition); break; } } }); __publicField$9(this, "onSinglePanMove", (event, opState) => { if (this.enabled && this.domElement) { const restart = opState != this._state; this.setCenter(event.clientX, event.clientY); switch (opState) { case STATE.PAN: if (this.enablePan && this.camera) if (restart) { this.dispatchEvent(_endEvent); this.dispatchEvent(_startEvent); this.updateTbState(opState, true); const rayDir = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement); if (rayDir !== void 0) this._startCursorPosition.copy(rayDir); if (this.enableGrid) this.drawGrid(); this.activateGizmos(false); } else { const rayDir = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement); if (rayDir !== void 0) this._currentCursorPosition.copy(rayDir); this.applyTransformMatrix(this.pan(this._startCursorPosition, this._currentCursorPosition)); } break; case STATE.ROTATE: if (this.enableRotate && this.camera) if (restart) { this.dispatchEvent(_endEvent); this.dispatchEvent(_startEvent); this.updateTbState(opState, true); const rayDir = this.unprojectOnTbSurface(this.camera, _center.x, _center.y, this.domElement, this._tbRadius); if (rayDir !== void 0) this._startCursorPosition.copy(rayDir); if (this.enableGrid) this.disposeGrid(); this.activateGizmos(true); } else { const rayDir = this.unprojectOnTbSurface(this.camera, _center.x, _center.y, this.domElement, this._tbRadius); if (rayDir !== void 0) this._currentCursorPosition.copy(rayDir); const distance = this._startCursorPosition.distanceTo(this._currentCursorPosition); const angle = this._startCursorPosition.angleTo(this._currentCursorPosition); const amount = Math.max(distance / this._tbRadius, angle); this.applyTransformMatrix(this.rotate(this.calculateRotationAxis(this._startCursorPosition, this._currentCursorPosition), amount)); if (this.enableAnimations) { this._timePrev = this._timeCurrent; this._timeCurrent = performance.now(); this._anglePrev = this._angleCurrent; this._angleCurrent = amount; this._cursorPosPrev.copy(this._cursorPosCurr); this._cursorPosCurr.copy(this._currentCursorPosition); this._wPrev = this._wCurr; this._wCurr = this.calculateAngularSpeed(this._anglePrev, this._angleCurrent, this._timePrev, this._timeCurrent); } } break; case STATE.SCALE: if (this.enableZoom) if (restart) { this.dispatchEvent(_endEvent); this.dispatchEvent(_startEvent); this.updateTbState(opState, true); this._startCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); this._currentCursorPosition.copy(this._startCursorPosition); if (this.enableGrid) this.disposeGrid(); this.activateGizmos(false); } else { const screenNotches = 8; this._currentCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); const movement = this._currentCursorPosition.y - this._startCursorPosition.y; let size = 1; if (movement < 0) size = 1 / Math.pow(this.scaleFactor, -movement * screenNotches); else if (movement > 0) size = Math.pow(this.scaleFactor, movement * screenNotches); this.applyTransformMatrix(this.applyScale(size, this._gizmos.position)); } break; case STATE.FOV: if (this.enableZoom && this.camera instanceof PerspectiveCamera$1) if (restart) { this.dispatchEvent(_endEvent); this.dispatchEvent(_startEvent); this.updateTbState(opState, true); this._startCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); this._currentCursorPosition.copy(this._startCursorPosition); if (this.enableGrid) this.disposeGrid(); this.activateGizmos(false); } else { const screenNotches = 8; this._currentCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); const movement = this._currentCursorPosition.y - this._startCursorPosition.y; let size = 1; if (movement < 0) size = 1 / Math.pow(this.scaleFactor, -movement * screenNotches); else if (movement > 0) size = Math.pow(this.scaleFactor, movement * screenNotches); this._v3_1.setFromMatrixPosition(this._cameraMatrixState); const x = this._v3_1.distanceTo(this._gizmos.position); let xNew = x / size; xNew = MathUtils.clamp(xNew, this.minDistance, this.maxDistance); const y = x * Math.tan(MathUtils.DEG2RAD * this._fovState * .5); let newFov = MathUtils.RAD2DEG * (Math.atan(y / xNew) * 2); newFov = MathUtils.clamp(newFov, this.minFov, this.maxFov); const newDistance = y / Math.tan(MathUtils.DEG2RAD * (newFov / 2)); size = x / newDistance; this._v3_2.setFromMatrixPosition(this._gizmoMatrixState); this.setFov(newFov); this.applyTransformMatrix(this.applyScale(size, this._v3_2, false)); const direction = this._gizmos.position.clone().sub(this.camera.position).normalize().multiplyScalar(newDistance / x); this._m4_1.makeTranslation(direction.x, direction.y, direction.z); } break; } this.dispatchEvent(_changeEvent); } }); __publicField$9(this, "onSinglePanEnd", () => { if (this._state == STATE.ROTATE) { if (!this.enableRotate) return; if (this.enableAnimations) if (performance.now() - this._timeCurrent < 120) { const w = Math.abs((this._wPrev + this._wCurr) / 2); const self = this; this._animationId = window.requestAnimationFrame(function(t) { self.updateTbState(STATE.ANIMATION_ROTATE, true); const rotationAxis = self.calculateRotationAxis(self._cursorPosPrev, self._cursorPosCurr); self.onRotationAnim(t, rotationAxis, Math.min(w, self.wMax)); }); } else { this.updateTbState(STATE.IDLE, false); this.activateGizmos(false); this.dispatchEvent(_changeEvent); } else { this.updateTbState(STATE.IDLE, false); this.activateGizmos(false); this.dispatchEvent(_changeEvent); } } else if (this._state == STATE.PAN || this._state == STATE.IDLE) { this.updateTbState(STATE.IDLE, false); if (this.enableGrid) this.disposeGrid(); this.activateGizmos(false); this.dispatchEvent(_changeEvent); } this.dispatchEvent(_endEvent); }); __publicField$9(this, "onDoubleTap", (event) => { if (this.enabled && this.enablePan && this.scene && this.camera && this.domElement) { this.dispatchEvent(_startEvent); this.setCenter(event.clientX, event.clientY); const hitP = this.unprojectOnObj(this.getCursorNDC(_center.x, _center.y, this.domElement), this.camera); if (hitP && this.enableAnimations) { const self = this; if (this._animationId != -1) window.cancelAnimationFrame(this._animationId); this._timeStart = -1; this._animationId = window.requestAnimationFrame(function(t) { self.updateTbState(STATE.ANIMATION_FOCUS, true); self.onFocusAnim(t, hitP, self._cameraMatrixState, self._gizmoMatrixState); }); } else if (hitP && !this.enableAnimations) { this.updateTbState(STATE.FOCUS, true); this.focus(hitP, this.scaleFactor); this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_changeEvent); } } this.dispatchEvent(_endEvent); }); __publicField$9(this, "onDoublePanStart", () => { if (this.enabled && this.enablePan && this.camera && this.domElement) { this.dispatchEvent(_startEvent); this.updateTbState(STATE.PAN, true); this.setCenter((this._touchCurrent[0].clientX + this._touchCurrent[1].clientX) / 2, (this._touchCurrent[0].clientY + this._touchCurrent[1].clientY) / 2); const rayDir = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement, true); if (rayDir !== void 0) this._startCursorPosition.copy(rayDir); this._currentCursorPosition.copy(this._startCursorPosition); this.activateGizmos(false); } }); __publicField$9(this, "onDoublePanMove", () => { if (this.enabled && this.enablePan && this.camera && this.domElement) { this.setCenter((this._touchCurrent[0].clientX + this._touchCurrent[1].clientX) / 2, (this._touchCurrent[0].clientY + this._touchCurrent[1].clientY) / 2); if (this._state != STATE.PAN) { this.updateTbState(STATE.PAN, true); this._startCursorPosition.copy(this._currentCursorPosition); } const rayDir = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement, true); if (rayDir !== void 0) this._currentCursorPosition.copy(rayDir); this.applyTransformMatrix(this.pan(this._startCursorPosition, this._currentCursorPosition, true)); this.dispatchEvent(_changeEvent); } }); __publicField$9(this, "onDoublePanEnd", () => { this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_endEvent); }); __publicField$9(this, "onRotateStart", () => { var _a; if (this.enabled && this.enableRotate) { this.dispatchEvent(_startEvent); this.updateTbState(STATE.ZROTATE, true); this._startFingerRotation = this.getAngle(this._touchCurrent[1], this._touchCurrent[0]) + this.getAngle(this._touchStart[1], this._touchStart[0]); this._currentFingerRotation = this._startFingerRotation; (_a = this.camera) == null || _a.getWorldDirection(this._rotationAxis); if (!this.enablePan && !this.enableZoom) this.activateGizmos(true); } }); __publicField$9(this, "onRotateMove", () => { var _a; if (this.enabled && this.enableRotate && this.camera && this.domElement) { this.setCenter((this._touchCurrent[0].clientX + this._touchCurrent[1].clientX) / 2, (this._touchCurrent[0].clientY + this._touchCurrent[1].clientY) / 2); let rotationPoint; if (this._state != STATE.ZROTATE) { this.updateTbState(STATE.ZROTATE, true); this._startFingerRotation = this._currentFingerRotation; } this._currentFingerRotation = this.getAngle(this._touchCurrent[1], this._touchCurrent[0]) + this.getAngle(this._touchStart[1], this._touchStart[0]); if (!this.enablePan) rotationPoint = new Vector3().setFromMatrixPosition(this._gizmoMatrixState); else if (this.camera) { this._v3_2.setFromMatrixPosition(this._gizmoMatrixState); rotationPoint = (_a = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement)) == null ? void 0 : _a.applyQuaternion(this.camera.quaternion).multiplyScalar(1 / this.camera.zoom).add(this._v3_2); } const amount = MathUtils.DEG2RAD * (this._startFingerRotation - this._currentFingerRotation); if (rotationPoint !== void 0) this.applyTransformMatrix(this.zRotate(rotationPoint, amount)); this.dispatchEvent(_changeEvent); } }); __publicField$9(this, "onRotateEnd", () => { this.updateTbState(STATE.IDLE, false); this.activateGizmos(false); this.dispatchEvent(_endEvent); }); __publicField$9(this, "onPinchStart", () => { if (this.enabled && this.enableZoom) { this.dispatchEvent(_startEvent); this.updateTbState(STATE.SCALE, true); this._startFingerDistance = this.calculatePointersDistance(this._touchCurrent[0], this._touchCurrent[1]); this._currentFingerDistance = this._startFingerDistance; this.activateGizmos(false); } }); __publicField$9(this, "onPinchMove", () => { var _a, _b; if (this.enabled && this.enableZoom && this.domElement) { this.setCenter((this._touchCurrent[0].clientX + this._touchCurrent[1].clientX) / 2, (this._touchCurrent[0].clientY + this._touchCurrent[1].clientY) / 2); const minDistance = 12; if (this._state != STATE.SCALE) { this._startFingerDistance = this._currentFingerDistance; this.updateTbState(STATE.SCALE, true); } this._currentFingerDistance = Math.max(this.calculatePointersDistance(this._touchCurrent[0], this._touchCurrent[1]), minDistance * this._devPxRatio); const amount = this._currentFingerDistance / this._startFingerDistance; let scalePoint; if (!this.enablePan) scalePoint = this._gizmos.position; else if (this.camera instanceof OrthographicCamera$1) scalePoint = (_a = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement)) == null ? void 0 : _a.applyQuaternion(this.camera.quaternion).multiplyScalar(1 / this.camera.zoom).add(this._gizmos.position); else if (this.camera instanceof PerspectiveCamera$1) scalePoint = (_b = this.unprojectOnTbPlane(this.camera, _center.x, _center.y, this.domElement)) == null ? void 0 : _b.applyQuaternion(this.camera.quaternion).add(this._gizmos.position); if (scalePoint !== void 0) this.applyTransformMatrix(this.applyScale(amount, scalePoint)); this.dispatchEvent(_changeEvent); } }); __publicField$9(this, "onPinchEnd", () => { this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_endEvent); }); __publicField$9(this, "onTriplePanStart", () => { if (this.enabled && this.enableZoom && this.domElement) { this.dispatchEvent(_startEvent); this.updateTbState(STATE.SCALE, true); let clientX = 0; let clientY = 0; const nFingers = this._touchCurrent.length; for (let i = 0; i < nFingers; i++) { clientX += this._touchCurrent[i].clientX; clientY += this._touchCurrent[i].clientY; } this.setCenter(clientX / nFingers, clientY / nFingers); this._startCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); this._currentCursorPosition.copy(this._startCursorPosition); } }); __publicField$9(this, "onTriplePanMove", () => { if (this.enabled && this.enableZoom && this.camera && this.domElement) { let clientX = 0; let clientY = 0; const nFingers = this._touchCurrent.length; for (let i = 0; i < nFingers; i++) { clientX += this._touchCurrent[i].clientX; clientY += this._touchCurrent[i].clientY; } this.setCenter(clientX / nFingers, clientY / nFingers); const screenNotches = 8; this._currentCursorPosition.setY(this.getCursorNDC(_center.x, _center.y, this.domElement).y * .5); const movement = this._currentCursorPosition.y - this._startCursorPosition.y; let size = 1; if (movement < 0) size = 1 / Math.pow(this.scaleFactor, -movement * screenNotches); else if (movement > 0) size = Math.pow(this.scaleFactor, movement * screenNotches); this._v3_1.setFromMatrixPosition(this._cameraMatrixState); const x = this._v3_1.distanceTo(this._gizmos.position); let xNew = x / size; xNew = MathUtils.clamp(xNew, this.minDistance, this.maxDistance); const y = x * Math.tan(MathUtils.DEG2RAD * this._fovState * .5); let newFov = MathUtils.RAD2DEG * (Math.atan(y / xNew) * 2); newFov = MathUtils.clamp(newFov, this.minFov, this.maxFov); const newDistance = y / Math.tan(MathUtils.DEG2RAD * (newFov / 2)); size = x / newDistance; this._v3_2.setFromMatrixPosition(this._gizmoMatrixState); this.setFov(newFov); this.applyTransformMatrix(this.applyScale(size, this._v3_2, false)); const direction = this._gizmos.position.clone().sub(this.camera.position).normalize().multiplyScalar(newDistance / x); this._m4_1.makeTranslation(direction.x, direction.y, direction.z); this.dispatchEvent(_changeEvent); } }); __publicField$9(this, "onTriplePanEnd", () => { this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_endEvent); }); /** * Set _center's x/y coordinates * @param {Number} clientX * @param {Number} clientY */ __publicField$9(this, "setCenter", (clientX, clientY) => { _center.x = clientX; _center.y = clientY; }); /** * Set default mouse actions */ __publicField$9(this, "initializeMouseActions", () => { this.setMouseAction("PAN", 0, "CTRL"); this.setMouseAction("PAN", 2); this.setMouseAction("ROTATE", 0); this.setMouseAction("ZOOM", "WHEEL"); this.setMouseAction("ZOOM", 1); this.setMouseAction("FOV", "WHEEL", "SHIFT"); this.setMouseAction("FOV", 1, "SHIFT"); }); /** * Set a new mouse action by specifying the operation to be performed and a mouse/key combination. In case of conflict, replaces the existing one * @param {String} operation The operation to be performed ('PAN', 'ROTATE', 'ZOOM', 'FOV) * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed * @returns {Boolean} True if the mouse action has been successfully added, false otherwise */ __publicField$9(this, "setMouseAction", (operation, mouse, key = null) => { const operationInput = [ "PAN", "ROTATE", "ZOOM", "FOV" ]; const mouseInput = [ 0, 1, 2, "WHEEL" ]; const keyInput = [ "CTRL", "SHIFT", null ]; let state; if (!operationInput.includes(operation) || !mouseInput.includes(mouse) || !keyInput.includes(key)) return false; if (mouse == "WHEEL") { if (operation != "ZOOM" && operation != "FOV") return false; } switch (operation) { case "PAN": state = STATE.PAN; break; case "ROTATE": state = STATE.ROTATE; break; case "ZOOM": state = STATE.SCALE; break; case "FOV": state = STATE.FOV; break; } const action = { operation, mouse, key, state }; for (let i = 0; i < this.mouseActions.length; i++) if (this.mouseActions[i].mouse == action.mouse && this.mouseActions[i].key == action.key) { this.mouseActions.splice(i, 1, action); return true; } this.mouseActions.push(action); return true; }); /** * Return the operation associated to a mouse/keyboard combination * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed * @returns The operation if it has been found, null otherwise */ __publicField$9(this, "getOpFromAction", (mouse, key) => { let action; for (let i = 0; i < this.mouseActions.length; i++) { action = this.mouseActions[i]; if (action.mouse == mouse && action.key == key) return action.operation; } if (key) for (let i = 0; i < this.mouseActions.length; i++) { action = this.mouseActions[i]; if (action.mouse == mouse && action.key == null) return action.operation; } return null; }); /** * Get the operation associated to mouse and key combination and returns the corresponding FSA state * @param {Number} mouse Mouse button * @param {String} key Keyboard modifier * @returns The FSA state obtained from the operation associated to mouse/keyboard combination */ __publicField$9(this, "getOpStateFromAction", (mouse, key) => { let action; for (let i = 0; i < this.mouseActions.length; i++) { action = this.mouseActions[i]; if (action.mouse == mouse && action.key == key) return action.state; } if (key) for (let i = 0; i < this.mouseActions.length; i++) { action = this.mouseActions[i]; if (action.mouse == mouse && action.key == null) return action.state; } return null; }); /** * Calculate the angle between two pointers * @param {PointerEvent} p1 * @param {PointerEvent} p2 * @returns {Number} The angle between two pointers in degrees */ __publicField$9(this, "getAngle", (p1, p2) => { return Math.atan2(p2.clientY - p1.clientY, p2.clientX - p1.clientX) * 180 / Math.PI; }); /** * Update a PointerEvent inside current pointerevents array * @param {PointerEvent} event */ __publicField$9(this, "updateTouchEvent", (event) => { for (let i = 0; i < this._touchCurrent.length; i++) if (this._touchCurrent[i].pointerId == event.pointerId) { this._touchCurrent.splice(i, 1, event); break; } }); /** * Calculate the angular speed * @param {Number} p0 Position at t0 * @param {Number} p1 Position at t1 * @param {Number} t0 Initial time in milliseconds * @param {Number} t1 Ending time in milliseconds */ __publicField$9(this, "calculateAngularSpeed", (p0, p1, t0, t1) => { const s = p1 - p0; const t = (t1 - t0) / 1e3; if (t == 0) return 0; return s / t; }); /** * Calculate the distance between two pointers * @param {PointerEvent} p0 The first pointer * @param {PointerEvent} p1 The second pointer * @returns {number} The distance between the two pointers */ __publicField$9(this, "calculatePointersDistance", (p0, p1) => { return Math.sqrt(Math.pow(p1.clientX - p0.clientX, 2) + Math.pow(p1.clientY - p0.clientY, 2)); }); /** * Calculate the rotation axis as the vector perpendicular between two vectors * @param {Vector3} vec1 The first vector * @param {Vector3} vec2 The second vector * @returns {Vector3} The normalized rotation axis */ __publicField$9(this, "calculateRotationAxis", (vec1, vec2) => { this._rotationMatrix.extractRotation(this._cameraMatrixState); this._quat.setFromRotationMatrix(this._rotationMatrix); this._rotationAxis.crossVectors(vec1, vec2).applyQuaternion(this._quat); return this._rotationAxis.normalize().clone(); }); /** * Calculate the trackball radius so that gizmo's diamater will be 2/3 of the minimum side of the camera frustum * @param {Camera} camera * @returns {Number} The trackball radius */ __publicField$9(this, "calculateTbRadius", (camera) => { const factor = .67; const distance = camera.position.distanceTo(this._gizmos.position); if (camera instanceof PerspectiveCamera$1) { const halfFovV = MathUtils.DEG2RAD * camera.fov * .5; const halfFovH = Math.atan(camera.aspect * Math.tan(halfFovV)); return Math.tan(Math.min(halfFovV, halfFovH)) * distance * factor; } else if (camera instanceof OrthographicCamera$1) return Math.min(camera.top, camera.right) * factor; }); /** * Focus operation consist of positioning the point of interest in front of the camera and a slightly zoom in * @param {Vector3} point The point of interest * @param {Number} size Scale factor * @param {Number} amount Amount of operation to be completed (used for focus animations, default is complete full operation) */ __publicField$9(this, "focus", (point, size, amount = 1) => { if (this.camera) { const focusPoint = point.clone(); focusPoint.sub(this._gizmos.position).multiplyScalar(amount); this._translationMatrix.makeTranslation(focusPoint.x, focusPoint.y, focusPoint.z); const gizmoStateTemp = this._gizmoMatrixState.clone(); this._gizmoMatrixState.premultiply(this._translationMatrix); this._gizmoMatrixState.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); const cameraStateTemp = this._cameraMatrixState.clone(); this._cameraMatrixState.premultiply(this._translationMatrix); this._cameraMatrixState.decompose(this.camera.position, this.camera.quaternion, this.camera.scale); if (this.enableZoom) this.applyTransformMatrix(this.applyScale(size, this._gizmos.position)); this._gizmoMatrixState.copy(gizmoStateTemp); this._cameraMatrixState.copy(cameraStateTemp); } }); /** * Draw a grid and add it to the scene */ __publicField$9(this, "drawGrid", () => { if (this.scene) { const color = 8947848; const multiplier = 3; let size, divisions, maxLength, tick; if (this.camera instanceof OrthographicCamera$1) { const width = this.camera.right - this.camera.left; const height = this.camera.bottom - this.camera.top; maxLength = Math.max(width, height); tick = maxLength / 20; size = maxLength / this.camera.zoom * multiplier; divisions = size / tick * this.camera.zoom; } else if (this.camera instanceof PerspectiveCamera$1) { const distance = this.camera.position.distanceTo(this._gizmos.position); const halfFovV = MathUtils.DEG2RAD * this.camera.fov * .5; const halfFovH = Math.atan(this.camera.aspect * Math.tan(halfFovV)); maxLength = Math.tan(Math.max(halfFovV, halfFovH)) * distance * 2; tick = maxLength / 20; size = maxLength * multiplier; divisions = size / tick; } if (this._grid == null && this.camera) { this._grid = new GridHelper(size, divisions, color, color); this._grid.position.copy(this._gizmos.position); this._gridPosition.copy(this._grid.position); this._grid.quaternion.copy(this.camera.quaternion); this._grid.rotateX(Math.PI * .5); this.scene.add(this._grid); } } }); __publicField$9(this, "connect", (domElement) => { if (domElement === document) console.error("THREE.ArcballControls: \"document\" should not be used as the target \"domElement\". Please use \"renderer.domElement\" instead."); this.domElement = domElement; this.domElement.style.touchAction = "none"; this.domElement.addEventListener("contextmenu", this.onContextMenu); this.domElement.addEventListener("pointerdown", this.onPointerDown); this.domElement.addEventListener("pointercancel", this.onPointerCancel); this.domElement.addEventListener("wheel", this.onWheel); }); /** * Remove all listeners, stop animations and clean scene */ __publicField$9(this, "dispose", () => { var _a, _b, _c, _d, _e; if (this._animationId != -1) window.cancelAnimationFrame(this._animationId); (_a = this.domElement) == null || _a.removeEventListener("pointerdown", this.onPointerDown); (_b = this.domElement) == null || _b.removeEventListener("pointercancel", this.onPointerCancel); (_c = this.domElement) == null || _c.removeEventListener("wheel", this.onWheel); (_d = this.domElement) == null || _d.removeEventListener("contextmenu", this.onContextMenu); window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); window.removeEventListener("resize", this.onWindowResize); (_e = this.scene) == null || _e.remove(this._gizmos); this.disposeGrid(); }); /** * remove the grid from the scene */ __publicField$9(this, "disposeGrid", () => { if (this._grid && this.scene) { this.scene.remove(this._grid); this._grid = null; } }); /** * Compute the easing out cubic function for ease out effect in animation * @param {Number} t The absolute progress of the animation in the bound of 0 (beginning of the) and 1 (ending of animation) * @returns {Number} Result of easing out cubic at time t */ __publicField$9(this, "easeOutCubic", (t) => { return 1 - Math.pow(1 - t, 3); }); /** * Make rotation gizmos more or less visible * @param {Boolean} isActive If true, make gizmos more visible */ __publicField$9(this, "activateGizmos", (isActive) => { for (const gizmo of this._gizmos.children) gizmo.material.setValues({ opacity: isActive ? 1 : .6 }); }); /** * Calculate the cursor position in NDC * @param {number} x Cursor horizontal coordinate within the canvas * @param {number} y Cursor vertical coordinate within the canvas * @param {HTMLElement} canvas The canvas where the renderer draws its output * @returns {Vector2} Cursor normalized position inside the canvas */ __publicField$9(this, "getCursorNDC", (cursorX, cursorY, canvas) => { const canvasRect = canvas.getBoundingClientRect(); this._v2_1.setX((cursorX - canvasRect.left) / canvasRect.width * 2 - 1); this._v2_1.setY((canvasRect.bottom - cursorY) / canvasRect.height * 2 - 1); return this._v2_1.clone(); }); /** * Calculate the cursor position inside the canvas x/y coordinates with the origin being in the center of the canvas * @param {Number} x Cursor horizontal coordinate within the canvas * @param {Number} y Cursor vertical coordinate within the canvas * @param {HTMLElement} canvas The canvas where the renderer draws its output * @returns {Vector2} Cursor position inside the canvas */ __publicField$9(this, "getCursorPosition", (cursorX, cursorY, canvas) => { this._v2_1.copy(this.getCursorNDC(cursorX, cursorY, canvas)); if (this.camera instanceof OrthographicCamera$1) { this._v2_1.x *= (this.camera.right - this.camera.left) * .5; this._v2_1.y *= (this.camera.top - this.camera.bottom) * .5; } return this._v2_1.clone(); }); /** * Set the camera to be controlled * @param {Camera} camera The virtual camera to be controlled */ __publicField$9(this, "setCamera", (camera) => { if (camera) { camera.lookAt(this.target); camera.updateMatrix(); if (camera instanceof PerspectiveCamera$1) { this._fov0 = camera.fov; this._fovState = camera.fov; } this._cameraMatrixState0.copy(camera.matrix); this._cameraMatrixState.copy(this._cameraMatrixState0); this._cameraProjectionState.copy(camera.projectionMatrix); this._zoom0 = camera.zoom; this._zoomState = this._zoom0; this._initialNear = camera.near; this._nearPos0 = camera.position.distanceTo(this.target) - camera.near; this._nearPos = this._initialNear; this._initialFar = camera.far; this._farPos0 = camera.position.distanceTo(this.target) - camera.far; this._farPos = this._initialFar; this._up0.copy(camera.up); this._upState.copy(camera.up); this.camera = camera; this.camera.updateProjectionMatrix(); const tbRadius = this.calculateTbRadius(camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; this.makeGizmos(this.target, this._tbRadius); } }); /** * Creates the rotation gizmos matching trackball center and radius * @param {Vector3} tbCenter The trackball center * @param {number} tbRadius The trackball radius */ __publicField$9(this, "makeGizmos", (tbCenter, tbRadius) => { const points = new EllipseCurve(0, 0, tbRadius, tbRadius).getPoints(this._curvePts); const curveGeometry = new BufferGeometry().setFromPoints(points); const curveMaterialX = new LineBasicMaterial({ color: 16744576, fog: false, transparent: true, opacity: .6 }); const curveMaterialY = new LineBasicMaterial({ color: 8454016, fog: false, transparent: true, opacity: .6 }); const curveMaterialZ = new LineBasicMaterial({ color: 8421631, fog: false, transparent: true, opacity: .6 }); const gizmoX = new Line$1(curveGeometry, curveMaterialX); const gizmoY = new Line$1(curveGeometry, curveMaterialY); const gizmoZ = new Line$1(curveGeometry, curveMaterialZ); const rotation = Math.PI * .5; gizmoX.rotation.x = rotation; gizmoY.rotation.y = rotation; this._gizmoMatrixState0.identity().setPosition(tbCenter); this._gizmoMatrixState.copy(this._gizmoMatrixState0); if (this.camera && this.camera.zoom != 1) { const size = 1 / this.camera.zoom; this._scaleMatrix.makeScale(size, size, size); this._translationMatrix.makeTranslation(-tbCenter.x, -tbCenter.y, -tbCenter.z); this._gizmoMatrixState.premultiply(this._translationMatrix).premultiply(this._scaleMatrix); this._translationMatrix.makeTranslation(tbCenter.x, tbCenter.y, tbCenter.z); this._gizmoMatrixState.premultiply(this._translationMatrix); } this._gizmoMatrixState.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this._gizmos.clear(); this._gizmos.add(gizmoX); this._gizmos.add(gizmoY); this._gizmos.add(gizmoZ); }); /** * Perform animation for focus operation * @param {Number} time Instant in which this function is called as performance.now() * @param {Vector3} point Point of interest for focus operation * @param {Matrix4} cameraMatrix Camera matrix * @param {Matrix4} gizmoMatrix Gizmos matrix */ __publicField$9(this, "onFocusAnim", (time, point, cameraMatrix, gizmoMatrix) => { if (this._timeStart == -1) this._timeStart = time; if (this._state == STATE.ANIMATION_FOCUS) { const animTime = (time - this._timeStart) / this.focusAnimationTime; this._gizmoMatrixState.copy(gizmoMatrix); if (animTime >= 1) { this._gizmoMatrixState.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this.focus(point, this.scaleFactor); this._timeStart = -1; this.updateTbState(STATE.IDLE, false); this.activateGizmos(false); this.dispatchEvent(_changeEvent); } else { const amount = this.easeOutCubic(animTime); const size = 1 - amount + this.scaleFactor * amount; this._gizmoMatrixState.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this.focus(point, size, amount); this.dispatchEvent(_changeEvent); const self = this; this._animationId = window.requestAnimationFrame(function(t) { self.onFocusAnim(t, point, cameraMatrix, gizmoMatrix.clone()); }); } } else { this._animationId = -1; this._timeStart = -1; } }); /** * Perform animation for rotation operation * @param {Number} time Instant in which this function is called as performance.now() * @param {Vector3} rotationAxis Rotation axis * @param {number} w0 Initial angular velocity */ __publicField$9(this, "onRotationAnim", (time, rotationAxis, w0) => { if (this._timeStart == -1) { this._anglePrev = 0; this._angleCurrent = 0; this._timeStart = time; } if (this._state == STATE.ANIMATION_ROTATE) { const deltaTime = (time - this._timeStart) / 1e3; if (w0 + -this.dampingFactor * deltaTime > 0) { this._angleCurrent = .5 * -this.dampingFactor * Math.pow(deltaTime, 2) + w0 * deltaTime + 0; this.applyTransformMatrix(this.rotate(rotationAxis, this._angleCurrent)); this.dispatchEvent(_changeEvent); const self = this; this._animationId = window.requestAnimationFrame(function(t) { self.onRotationAnim(t, rotationAxis, w0); }); } else { this._animationId = -1; this._timeStart = -1; this.updateTbState(STATE.IDLE, false); this.activateGizmos(false); this.dispatchEvent(_changeEvent); } } else { this._animationId = -1; this._timeStart = -1; if (this._state != STATE.ROTATE) { this.activateGizmos(false); this.dispatchEvent(_changeEvent); } } }); /** * Perform pan operation moving camera between two points * @param {Vector3} p0 Initial point * @param {Vector3} p1 Ending point * @param {Boolean} adjust If movement should be adjusted considering camera distance (Perspective only) */ __publicField$9(this, "pan", (p0, p1, adjust = false) => { if (this.camera) { const movement = p0.clone().sub(p1); if (this.camera instanceof OrthographicCamera$1) movement.multiplyScalar(1 / this.camera.zoom); if (this.camera instanceof PerspectiveCamera$1 && adjust) { this._v3_1.setFromMatrixPosition(this._cameraMatrixState0); this._v3_2.setFromMatrixPosition(this._gizmoMatrixState0); const distanceFactor = this._v3_1.distanceTo(this._v3_2) / this.camera.position.distanceTo(this._gizmos.position); movement.multiplyScalar(1 / distanceFactor); } this._v3_1.set(movement.x, movement.y, 0).applyQuaternion(this.camera.quaternion); this._m4_1.makeTranslation(this._v3_1.x, this._v3_1.y, this._v3_1.z); this.setTransformationMatrices(this._m4_1, this._m4_1); } return _transformation; }); /** * Reset trackball */ __publicField$9(this, "reset", () => { if (this.camera) { this.camera.zoom = this._zoom0; if (this.camera instanceof PerspectiveCamera$1) this.camera.fov = this._fov0; this.camera.near = this._nearPos; this.camera.far = this._farPos; this._cameraMatrixState.copy(this._cameraMatrixState0); this._cameraMatrixState.decompose(this.camera.position, this.camera.quaternion, this.camera.scale); this.camera.up.copy(this._up0); this.camera.updateMatrix(); this.camera.updateProjectionMatrix(); this._gizmoMatrixState.copy(this._gizmoMatrixState0); this._gizmoMatrixState0.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this._gizmos.updateMatrix(); const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; this.makeGizmos(this._gizmos.position, this._tbRadius); this.camera.lookAt(this._gizmos.position); this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_changeEvent); } }); /** * Rotate the camera around an axis passing by trackball's center * @param {Vector3} axis Rotation axis * @param {number} angle Angle in radians * @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera */ __publicField$9(this, "rotate", (axis, angle) => { const point = this._gizmos.position; this._translationMatrix.makeTranslation(-point.x, -point.y, -point.z); this._rotationMatrix.makeRotationAxis(axis, -angle); this._m4_1.makeTranslation(point.x, point.y, point.z); this._m4_1.multiply(this._rotationMatrix); this._m4_1.multiply(this._translationMatrix); this.setTransformationMatrices(this._m4_1); return _transformation; }); __publicField$9(this, "copyState", () => { if (this.camera) { const state = JSON.stringify(this.camera instanceof OrthographicCamera$1 ? { arcballState: { cameraFar: this.camera.far, cameraMatrix: this.camera.matrix, cameraNear: this.camera.near, cameraUp: this.camera.up, cameraZoom: this.camera.zoom, gizmoMatrix: this._gizmos.matrix } } : { arcballState: { cameraFar: this.camera.far, cameraFov: this.camera.fov, cameraMatrix: this.camera.matrix, cameraNear: this.camera.near, cameraUp: this.camera.up, cameraZoom: this.camera.zoom, gizmoMatrix: this._gizmos.matrix } }); navigator.clipboard.writeText(state); } }); __publicField$9(this, "pasteState", () => { const self = this; navigator.clipboard.readText().then(function resolved(value) { self.setStateFromJSON(value); }); }); /** * Save the current state of the control. This can later be recovered with .reset */ __publicField$9(this, "saveState", () => { if (!this.camera) return; this._cameraMatrixState0.copy(this.camera.matrix); this._gizmoMatrixState0.copy(this._gizmos.matrix); this._nearPos = this.camera.near; this._farPos = this.camera.far; this._zoom0 = this.camera.zoom; this._up0.copy(this.camera.up); if (this.camera instanceof PerspectiveCamera$1) this._fov0 = this.camera.fov; }); /** * Perform uniform scale operation around a given point * @param {Number} size Scale factor * @param {Vector3} point Point around which scale * @param {Boolean} scaleGizmos If gizmos should be scaled (Perspective only) * @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos */ __publicField$9(this, "applyScale", (size, point, scaleGizmos = true) => { if (!this.camera) return; const scalePoint = point.clone(); let sizeInverse = 1 / size; if (this.camera instanceof OrthographicCamera$1) { this.camera.zoom = this._zoomState; this.camera.zoom *= size; if (this.camera.zoom > this.maxZoom) { this.camera.zoom = this.maxZoom; sizeInverse = this._zoomState / this.maxZoom; } else if (this.camera.zoom < this.minZoom) { this.camera.zoom = this.minZoom; sizeInverse = this._zoomState / this.minZoom; } this.camera.updateProjectionMatrix(); this._v3_1.setFromMatrixPosition(this._gizmoMatrixState); this._scaleMatrix.makeScale(sizeInverse, sizeInverse, sizeInverse); this._translationMatrix.makeTranslation(-this._v3_1.x, -this._v3_1.y, -this._v3_1.z); this._m4_2.makeTranslation(this._v3_1.x, this._v3_1.y, this._v3_1.z).multiply(this._scaleMatrix); this._m4_2.multiply(this._translationMatrix); scalePoint.sub(this._v3_1); const amount = scalePoint.clone().multiplyScalar(sizeInverse); scalePoint.sub(amount); this._m4_1.makeTranslation(scalePoint.x, scalePoint.y, scalePoint.z); this._m4_2.premultiply(this._m4_1); this.setTransformationMatrices(this._m4_1, this._m4_2); return _transformation; } if (this.camera instanceof PerspectiveCamera$1) { this._v3_1.setFromMatrixPosition(this._cameraMatrixState); this._v3_2.setFromMatrixPosition(this._gizmoMatrixState); let distance = this._v3_1.distanceTo(scalePoint); let amount = distance - distance * sizeInverse; const newDistance = distance - amount; if (newDistance < this.minDistance) { sizeInverse = this.minDistance / distance; amount = distance - distance * sizeInverse; } else if (newDistance > this.maxDistance) { sizeInverse = this.maxDistance / distance; amount = distance - distance * sizeInverse; } let direction = scalePoint.clone().sub(this._v3_1).normalize().multiplyScalar(amount); this._m4_1.makeTranslation(direction.x, direction.y, direction.z); if (scaleGizmos) { const pos = this._v3_2; distance = pos.distanceTo(scalePoint); amount = distance - distance * sizeInverse; direction = scalePoint.clone().sub(this._v3_2).normalize().multiplyScalar(amount); this._translationMatrix.makeTranslation(pos.x, pos.y, pos.z); this._scaleMatrix.makeScale(sizeInverse, sizeInverse, sizeInverse); this._m4_2.makeTranslation(direction.x, direction.y, direction.z).multiply(this._translationMatrix); this._m4_2.multiply(this._scaleMatrix); this._translationMatrix.makeTranslation(-pos.x, -pos.y, -pos.z); this._m4_2.multiply(this._translationMatrix); this.setTransformationMatrices(this._m4_1, this._m4_2); } else this.setTransformationMatrices(this._m4_1); return _transformation; } }); /** * Set camera fov * @param {Number} value fov to be setted */ __publicField$9(this, "setFov", (value) => { if (this.camera instanceof PerspectiveCamera$1) { this.camera.fov = MathUtils.clamp(value, this.minFov, this.maxFov); this.camera.updateProjectionMatrix(); } }); /** * Set the trackball's center point * @param {Number} x X coordinate * @param {Number} y Y coordinate * @param {Number} z Z coordinate */ __publicField$9(this, "setTarget", (x, y, z) => { if (this.camera) { this.target.set(x, y, z); this._gizmos.position.set(x, y, z); const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; this.makeGizmos(this.target, this._tbRadius); this.camera.lookAt(this.target); } }); /** * Rotate camera around its direction axis passing by a given point by a given angle * @param {Vector3} point The point where the rotation axis is passing trough * @param {Number} angle Angle in radians * @returns The computed transormation matix */ __publicField$9(this, "zRotate", (point, angle) => { this._rotationMatrix.makeRotationAxis(this._rotationAxis, angle); this._translationMatrix.makeTranslation(-point.x, -point.y, -point.z); this._m4_1.makeTranslation(point.x, point.y, point.z); this._m4_1.multiply(this._rotationMatrix); this._m4_1.multiply(this._translationMatrix); this._v3_1.setFromMatrixPosition(this._gizmoMatrixState).sub(point); this._v3_2.copy(this._v3_1).applyAxisAngle(this._rotationAxis, angle); this._v3_2.sub(this._v3_1); this._m4_2.makeTranslation(this._v3_2.x, this._v3_2.y, this._v3_2.z); this.setTransformationMatrices(this._m4_1, this._m4_2); return _transformation; }); /** * Unproject the cursor on the 3D object surface * @param {Vector2} cursor Cursor coordinates in NDC * @param {Camera} camera Virtual camera * @returns {Vector3} The point of intersection with the model, if exist, null otherwise */ __publicField$9(this, "unprojectOnObj", (cursor, camera) => { if (!this.scene) return null; const raycaster = new Raycaster(); raycaster.near = camera.near; raycaster.far = camera.far; raycaster.setFromCamera(cursor, camera); const intersect = raycaster.intersectObjects(this.scene.children, true); for (let i = 0; i < intersect.length; i++) if (intersect[i].object.uuid != this._gizmos.uuid && intersect[i].face) return intersect[i].point.clone(); return null; }); /** * Unproject the cursor on the trackball surface * @param {Camera} camera The virtual camera * @param {Number} cursorX Cursor horizontal coordinate on screen * @param {Number} cursorY Cursor vertical coordinate on screen * @param {HTMLElement} canvas The canvas where the renderer draws its output * @param {number} tbRadius The trackball radius * @returns {Vector3} The unprojected point on the trackball surface */ __publicField$9(this, "unprojectOnTbSurface", (camera, cursorX, cursorY, canvas, tbRadius) => { if (camera instanceof OrthographicCamera$1) { this._v2_1.copy(this.getCursorPosition(cursorX, cursorY, canvas)); this._v3_1.set(this._v2_1.x, this._v2_1.y, 0); const x2 = Math.pow(this._v2_1.x, 2); const y2 = Math.pow(this._v2_1.y, 2); const r2 = Math.pow(this._tbRadius, 2); if (x2 + y2 <= r2 * .5) this._v3_1.setZ(Math.sqrt(r2 - (x2 + y2))); else this._v3_1.setZ(r2 * .5 / Math.sqrt(x2 + y2)); return this._v3_1; } if (camera instanceof PerspectiveCamera$1) { this._v2_1.copy(this.getCursorNDC(cursorX, cursorY, canvas)); this._v3_1.set(this._v2_1.x, this._v2_1.y, -1); this._v3_1.applyMatrix4(camera.projectionMatrixInverse); const rayDir = this._v3_1.clone().normalize(); const cameraGizmoDistance = camera.position.distanceTo(this._gizmos.position); const radius2 = Math.pow(tbRadius, 2); const h = this._v3_1.z; const l = Math.sqrt(Math.pow(this._v3_1.x, 2) + Math.pow(this._v3_1.y, 2)); if (l == 0) { rayDir.set(this._v3_1.x, this._v3_1.y, tbRadius); return rayDir; } const m = h / l; const q = cameraGizmoDistance; let a = Math.pow(m, 2) + 1; let b = 2 * m * q; let c = Math.pow(q, 2) - radius2; let delta = Math.pow(b, 2) - 4 * a * c; if (delta >= 0) { this._v2_1.setX((-b - Math.sqrt(delta)) / (2 * a)); this._v2_1.setY(m * this._v2_1.x + q); if (MathUtils.RAD2DEG * this._v2_1.angle() >= 45) { const rayLength2 = Math.sqrt(Math.pow(this._v2_1.x, 2) + Math.pow(cameraGizmoDistance - this._v2_1.y, 2)); rayDir.multiplyScalar(rayLength2); rayDir.z += cameraGizmoDistance; return rayDir; } } a = m; b = q; c = -radius2 * .5; delta = Math.pow(b, 2) - 4 * a * c; this._v2_1.setX((-b - Math.sqrt(delta)) / (2 * a)); this._v2_1.setY(m * this._v2_1.x + q); const rayLength = Math.sqrt(Math.pow(this._v2_1.x, 2) + Math.pow(cameraGizmoDistance - this._v2_1.y, 2)); rayDir.multiplyScalar(rayLength); rayDir.z += cameraGizmoDistance; return rayDir; } }); /** * Unproject the cursor on the plane passing through the center of the trackball orthogonal to the camera * @param {Camera} camera The virtual camera * @param {Number} cursorX Cursor horizontal coordinate on screen * @param {Number} cursorY Cursor vertical coordinate on screen * @param {HTMLElement} canvas The canvas where the renderer draws its output * @param {Boolean} initialDistance If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only) * @returns {Vector3} The unprojected point on the trackball plane */ __publicField$9(this, "unprojectOnTbPlane", (camera, cursorX, cursorY, canvas, initialDistance = false) => { if (camera instanceof OrthographicCamera$1) { this._v2_1.copy(this.getCursorPosition(cursorX, cursorY, canvas)); this._v3_1.set(this._v2_1.x, this._v2_1.y, 0); return this._v3_1.clone(); } if (camera instanceof PerspectiveCamera$1) { this._v2_1.copy(this.getCursorNDC(cursorX, cursorY, canvas)); this._v3_1.set(this._v2_1.x, this._v2_1.y, -1); this._v3_1.applyMatrix4(camera.projectionMatrixInverse); const rayDir = this._v3_1.clone().normalize(); const h = this._v3_1.z; const l = Math.sqrt(Math.pow(this._v3_1.x, 2) + Math.pow(this._v3_1.y, 2)); let cameraGizmoDistance; if (initialDistance) cameraGizmoDistance = this._v3_1.setFromMatrixPosition(this._cameraMatrixState0).distanceTo(this._v3_2.setFromMatrixPosition(this._gizmoMatrixState0)); else cameraGizmoDistance = camera.position.distanceTo(this._gizmos.position); if (l == 0) { rayDir.set(0, 0, 0); return rayDir; } const m = h / l; const q = cameraGizmoDistance; const x = -q / m; const rayLength = Math.sqrt(Math.pow(q, 2) + Math.pow(x, 2)); rayDir.multiplyScalar(rayLength); rayDir.z = 0; return rayDir; } }); /** * Update camera and gizmos state */ __publicField$9(this, "updateMatrixState", () => { if (!this.camera) return; this._cameraMatrixState.copy(this.camera.matrix); this._gizmoMatrixState.copy(this._gizmos.matrix); if (this.camera instanceof OrthographicCamera$1) { this._cameraProjectionState.copy(this.camera.projectionMatrix); this.camera.updateProjectionMatrix(); this._zoomState = this.camera.zoom; } if (this.camera instanceof PerspectiveCamera$1) this._fovState = this.camera.fov; }); /** * Update the trackball FSA * @param {STATE} newState New state of the FSA * @param {Boolean} updateMatrices If matriices state should be updated */ __publicField$9(this, "updateTbState", (newState, updateMatrices) => { this._state = newState; if (updateMatrices) this.updateMatrixState(); }); __publicField$9(this, "update", () => { const EPS = 1e-6; if (!this.target.equals(this._currentTarget) && this.camera) { this._gizmos.position.set(this.target.x, this.target.y, this.target.z); const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; this.makeGizmos(this.target, this._tbRadius); this._currentTarget.copy(this.target); } if (!this.camera) return; if (this.camera instanceof OrthographicCamera$1) { if (this.camera.zoom > this.maxZoom || this.camera.zoom < this.minZoom) { const newZoom = MathUtils.clamp(this.camera.zoom, this.minZoom, this.maxZoom); this.applyTransformMatrix(this.applyScale(newZoom / this.camera.zoom, this._gizmos.position, true)); } } if (this.camera instanceof PerspectiveCamera$1) { const distance = this.camera.position.distanceTo(this._gizmos.position); if (distance > this.maxDistance + EPS || distance < this.minDistance - EPS) { const newDistance = MathUtils.clamp(distance, this.minDistance, this.maxDistance); this.applyTransformMatrix(this.applyScale(newDistance / distance, this._gizmos.position)); this.updateMatrixState(); } if (this.camera.fov < this.minFov || this.camera.fov > this.maxFov) { this.camera.fov = MathUtils.clamp(this.camera.fov, this.minFov, this.maxFov); this.camera.updateProjectionMatrix(); } const oldRadius = this._tbRadius; const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; if (oldRadius < this._tbRadius - EPS || oldRadius > this._tbRadius + EPS) { const scale = (this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z) / 3; const newRadius = this._tbRadius / scale; const points = new EllipseCurve(0, 0, newRadius, newRadius).getPoints(this._curvePts); const curveGeometry = new BufferGeometry().setFromPoints(points); for (const gizmo in this._gizmos.children) { const child = this._gizmos.children[gizmo]; child.geometry = curveGeometry; } } } this.camera.lookAt(this._gizmos.position); }); __publicField$9(this, "setStateFromJSON", (json) => { const state = JSON.parse(json); if (state.arcballState && this.camera) { this._cameraMatrixState.fromArray(state.arcballState.cameraMatrix.elements); this._cameraMatrixState.decompose(this.camera.position, this.camera.quaternion, this.camera.scale); this.camera.up.copy(state.arcballState.cameraUp); this.camera.near = state.arcballState.cameraNear; this.camera.far = state.arcballState.cameraFar; this.camera.zoom = state.arcballState.cameraZoom; if (this.camera instanceof PerspectiveCamera$1) this.camera.fov = state.arcballState.cameraFov; this._gizmoMatrixState.fromArray(state.arcballState.gizmoMatrix.elements); this._gizmoMatrixState.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this.camera.updateMatrix(); this.camera.updateProjectionMatrix(); this._gizmos.updateMatrix(); const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; const gizmoTmp = new Matrix4().copy(this._gizmoMatrixState0); this.makeGizmos(this._gizmos.position, this._tbRadius); this._gizmoMatrixState0.copy(gizmoTmp); this.camera.lookAt(this._gizmos.position); this.updateTbState(STATE.IDLE, false); this.dispatchEvent(_changeEvent); } }); this.camera = null; this.domElement = domElement; this.scene = scene; this.mouseActions = []; this._mouseOp = null; this._v2_1 = new Vector2(); this._v3_1 = new Vector3(); this._v3_2 = new Vector3(); this._m4_1 = new Matrix4(); this._m4_2 = new Matrix4(); this._quat = new Quaternion(); this._translationMatrix = new Matrix4(); this._rotationMatrix = new Matrix4(); this._scaleMatrix = new Matrix4(); this._rotationAxis = new Vector3(); this._cameraMatrixState = new Matrix4(); this._cameraProjectionState = new Matrix4(); this._fovState = 1; this._upState = new Vector3(); this._zoomState = 1; this._nearPos = 0; this._farPos = 0; this._gizmoMatrixState = new Matrix4(); this._up0 = new Vector3(); this._zoom0 = 1; this._fov0 = 0; this._initialNear = 0; this._nearPos0 = 0; this._initialFar = 0; this._farPos0 = 0; this._cameraMatrixState0 = new Matrix4(); this._gizmoMatrixState0 = new Matrix4(); this._button = -1; this._touchStart = []; this._touchCurrent = []; this._input = INPUT.NONE; this._switchSensibility = 32; this._startFingerDistance = 0; this._currentFingerDistance = 0; this._startFingerRotation = 0; this._currentFingerRotation = 0; this._devPxRatio = 0; this._downValid = true; this._nclicks = 0; this._downEvents = []; this._clickStart = 0; this._maxDownTime = 250; this._maxInterval = 300; this._posThreshold = 24; this._movementThreshold = 24; this._currentCursorPosition = new Vector3(); this._startCursorPosition = new Vector3(); this._grid = null; this._gridPosition = new Vector3(); this._gizmos = new Group(); this._curvePts = 128; this._timeStart = -1; this._animationId = -1; this.focusAnimationTime = 500; this._timePrev = 0; this._timeCurrent = 0; this._anglePrev = 0; this._angleCurrent = 0; this._cursorPosPrev = new Vector3(); this._cursorPosCurr = new Vector3(); this._wPrev = 0; this._wCurr = 0; this.adjustNearFar = false; this.scaleFactor = 1.1; this.dampingFactor = 25; this.wMax = 20; this.enableAnimations = true; this.enableGrid = false; this.cursorZoom = false; this.minFov = 5; this.maxFov = 90; this.enabled = true; this.enablePan = true; this.enableRotate = true; this.enableZoom = true; this.minDistance = 0; this.maxDistance = Infinity; this.minZoom = 0; this.maxZoom = Infinity; this.target = new Vector3(0, 0, 0); this._currentTarget = new Vector3(0, 0, 0); this._tbRadius = 1; this._state = STATE.IDLE; this.setCamera(camera); if (this.scene) this.scene.add(this._gizmos); this._devPxRatio = window.devicePixelRatio; this.initializeMouseActions(); if (this.domElement) this.connect(this.domElement); window.addEventListener("resize", this.onWindowResize); } /** * Apply a transformation matrix, to the camera and gizmos * @param {Object} transformation Object containing matrices to apply to camera and gizmos */ applyTransformMatrix(transformation) { if ((transformation == null ? void 0 : transformation.camera) && this.camera) { this._m4_1.copy(this._cameraMatrixState).premultiply(transformation.camera); this._m4_1.decompose(this.camera.position, this.camera.quaternion, this.camera.scale); this.camera.updateMatrix(); if (this._state == STATE.ROTATE || this._state == STATE.ZROTATE || this._state == STATE.ANIMATION_ROTATE) this.camera.up.copy(this._upState).applyQuaternion(this.camera.quaternion); } if (transformation == null ? void 0 : transformation.gizmos) { this._m4_1.copy(this._gizmoMatrixState).premultiply(transformation.gizmos); this._m4_1.decompose(this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale); this._gizmos.updateMatrix(); } if ((this._state == STATE.SCALE || this._state == STATE.FOCUS || this._state == STATE.ANIMATION_FOCUS) && this.camera) { const tbRadius = this.calculateTbRadius(this.camera); if (tbRadius !== void 0) this._tbRadius = tbRadius; if (this.adjustNearFar) { const cameraDistance = this.camera.position.distanceTo(this._gizmos.position); const bb = new Box3(); bb.setFromObject(this._gizmos); const sphere = new Sphere$1(); bb.getBoundingSphere(sphere); const adjustedNearPosition = Math.max(this._nearPos0, sphere.radius + sphere.center.length()); const regularNearPosition = cameraDistance - this._initialNear; const minNearPos = Math.min(adjustedNearPosition, regularNearPosition); this.camera.near = cameraDistance - minNearPos; const adjustedFarPosition = Math.min(this._farPos0, -sphere.radius + sphere.center.length()); const regularFarPosition = cameraDistance - this._initialFar; const minFarPos = Math.min(adjustedFarPosition, regularFarPosition); this.camera.far = cameraDistance - minFarPos; this.camera.updateProjectionMatrix(); } else { let update = false; if (this.camera.near != this._initialNear) { this.camera.near = this._initialNear; update = true; } if (this.camera.far != this._initialFar) { this.camera.far = this._initialFar; update = true; } if (update) this.camera.updateProjectionMatrix(); } } } /** * Set gizmos visibility * @param {Boolean} value Value of gizmos visibility */ setGizmosVisible(value) { this._gizmos.visible = value; this.dispatchEvent(_changeEvent); } /** * Set values in transformation object * @param {Matrix4} camera Transformation to be applied to the camera * @param {Matrix4} gizmos Transformation to be applied to gizmos */ setTransformationMatrices(camera = null, gizmos = null) { if (camera) if (_transformation.camera) _transformation.camera.copy(camera); else _transformation.camera = camera.clone(); else _transformation.camera = null; if (gizmos) if (_transformation.gizmos) _transformation.gizmos.copy(gizmos); else _transformation.gizmos = gizmos.clone(); else _transformation.gizmos = null; } }; //#endregion //#region node_modules/three-stdlib/controls/FlyControls.js var __defProp$8 = Object.defineProperty; var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$8 = (obj, key, value) => { __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; function contextmenu(event) { event.preventDefault(); } var FlyControls$1 = class extends EventDispatcher$1 { constructor(object, domElement) { super(); __publicField$8(this, "object"); __publicField$8(this, "domElement", null); __publicField$8(this, "movementSpeed", 1); __publicField$8(this, "rollSpeed", .005); __publicField$8(this, "dragToLook", false); __publicField$8(this, "autoForward", false); __publicField$8(this, "changeEvent", { type: "change" }); __publicField$8(this, "EPS", 1e-6); __publicField$8(this, "tmpQuaternion", new Quaternion()); __publicField$8(this, "mouseStatus", 0); __publicField$8(this, "movementSpeedMultiplier", 1); __publicField$8(this, "moveState", { up: 0, down: 0, left: 0, right: 0, forward: 0, back: 0, pitchUp: 0, pitchDown: 0, yawLeft: 0, yawRight: 0, rollLeft: 0, rollRight: 0 }); __publicField$8(this, "moveVector", new Vector3(0, 0, 0)); __publicField$8(this, "rotationVector", new Vector3(0, 0, 0)); __publicField$8(this, "keydown", (event) => { if (event.altKey) return; switch (event.code) { case "ShiftLeft": case "ShiftRight": this.movementSpeedMultiplier = .1; break; case "KeyW": this.moveState.forward = 1; break; case "KeyS": this.moveState.back = 1; break; case "KeyA": this.moveState.left = 1; break; case "KeyD": this.moveState.right = 1; break; case "KeyR": this.moveState.up = 1; break; case "KeyF": this.moveState.down = 1; break; case "ArrowUp": this.moveState.pitchUp = 1; break; case "ArrowDown": this.moveState.pitchDown = 1; break; case "ArrowLeft": this.moveState.yawLeft = 1; break; case "ArrowRight": this.moveState.yawRight = 1; break; case "KeyQ": this.moveState.rollLeft = 1; break; case "KeyE": this.moveState.rollRight = 1; break; } this.updateMovementVector(); this.updateRotationVector(); }); __publicField$8(this, "keyup", (event) => { switch (event.code) { case "ShiftLeft": case "ShiftRight": this.movementSpeedMultiplier = 1; break; case "KeyW": this.moveState.forward = 0; break; case "KeyS": this.moveState.back = 0; break; case "KeyA": this.moveState.left = 0; break; case "KeyD": this.moveState.right = 0; break; case "KeyR": this.moveState.up = 0; break; case "KeyF": this.moveState.down = 0; break; case "ArrowUp": this.moveState.pitchUp = 0; break; case "ArrowDown": this.moveState.pitchDown = 0; break; case "ArrowLeft": this.moveState.yawLeft = 0; break; case "ArrowRight": this.moveState.yawRight = 0; break; case "KeyQ": this.moveState.rollLeft = 0; break; case "KeyE": this.moveState.rollRight = 0; break; } this.updateMovementVector(); this.updateRotationVector(); }); __publicField$8(this, "pointerdown", (event) => { if (this.dragToLook) this.mouseStatus++; else { switch (event.button) { case 0: this.moveState.forward = 1; break; case 2: this.moveState.back = 1; break; } this.updateMovementVector(); } }); __publicField$8(this, "pointermove", (event) => { if (!this.dragToLook || this.mouseStatus > 0) { const container = this.getContainerDimensions(); const halfWidth = container.size[0] / 2; const halfHeight = container.size[1] / 2; this.moveState.yawLeft = -(event.pageX - container.offset[0] - halfWidth) / halfWidth; this.moveState.pitchDown = (event.pageY - container.offset[1] - halfHeight) / halfHeight; this.updateRotationVector(); } }); __publicField$8(this, "pointerup", (event) => { if (this.dragToLook) { this.mouseStatus--; this.moveState.yawLeft = this.moveState.pitchDown = 0; } else { switch (event.button) { case 0: this.moveState.forward = 0; break; case 2: this.moveState.back = 0; break; } this.updateMovementVector(); } this.updateRotationVector(); }); __publicField$8(this, "lastQuaternion", new Quaternion()); __publicField$8(this, "lastPosition", new Vector3()); __publicField$8(this, "update", (delta) => { const moveMult = delta * this.movementSpeed; const rotMult = delta * this.rollSpeed; this.object.translateX(this.moveVector.x * moveMult); this.object.translateY(this.moveVector.y * moveMult); this.object.translateZ(this.moveVector.z * moveMult); this.tmpQuaternion.set(this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1).normalize(); this.object.quaternion.multiply(this.tmpQuaternion); if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || 8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) { this.dispatchEvent(this.changeEvent); this.lastQuaternion.copy(this.object.quaternion); this.lastPosition.copy(this.object.position); } }); __publicField$8(this, "updateMovementVector", () => { const forward = this.moveState.forward || this.autoForward && !this.moveState.back ? 1 : 0; this.moveVector.x = -this.moveState.left + this.moveState.right; this.moveVector.y = -this.moveState.down + this.moveState.up; this.moveVector.z = -forward + this.moveState.back; }); __publicField$8(this, "updateRotationVector", () => { this.rotationVector.x = -this.moveState.pitchDown + this.moveState.pitchUp; this.rotationVector.y = -this.moveState.yawRight + this.moveState.yawLeft; this.rotationVector.z = -this.moveState.rollRight + this.moveState.rollLeft; }); __publicField$8(this, "getContainerDimensions", () => { if (this.domElement != document && !(this.domElement instanceof Document)) return { size: [this.domElement.offsetWidth, this.domElement.offsetHeight], offset: [this.domElement.offsetLeft, this.domElement.offsetTop] }; else return { size: [window.innerWidth, window.innerHeight], offset: [0, 0] }; }); __publicField$8(this, "connect", (domElement) => { this.domElement = domElement; if (!(domElement instanceof Document)) domElement.setAttribute("tabindex", -1); this.domElement.addEventListener("contextmenu", contextmenu); this.domElement.addEventListener("pointermove", this.pointermove); this.domElement.addEventListener("pointerdown", this.pointerdown); this.domElement.addEventListener("pointerup", this.pointerup); window.addEventListener("keydown", this.keydown); window.addEventListener("keyup", this.keyup); }); __publicField$8(this, "dispose", () => { this.domElement.removeEventListener("contextmenu", contextmenu); this.domElement.removeEventListener("pointermove", this.pointermove); this.domElement.removeEventListener("pointerdown", this.pointerdown); this.domElement.removeEventListener("pointerup", this.pointerup); window.removeEventListener("keydown", this.keydown); window.removeEventListener("keyup", this.keyup); }); this.object = object; if (domElement !== void 0) this.connect(domElement); this.updateMovementVector(); this.updateRotationVector(); } }; //#endregion //#region node_modules/three-stdlib/postprocessing/Pass.js var __defProp$7 = Object.defineProperty; var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$7 = (obj, key, value) => { __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var Pass = class { constructor() { __publicField$7(this, "enabled", true); __publicField$7(this, "needsSwap", true); __publicField$7(this, "clear", false); __publicField$7(this, "renderToScreen", false); } setSize(width, height) {} render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) { console.error("THREE.Pass: .render() must be implemented in derived pass."); } dispose() {} }; var FullScreenQuad = class { constructor(material) { __publicField$7(this, "camera", new OrthographicCamera$1(-1, 1, 1, -1, 0, 1)); __publicField$7(this, "geometry", new PlaneGeometry(2, 2)); __publicField$7(this, "mesh"); this.mesh = new Mesh(this.geometry, material); } get material() { return this.mesh.material; } set material(value) { this.mesh.material = value; } dispose() { this.mesh.geometry.dispose(); } render(renderer) { renderer.render(this.mesh, this.camera); } }; //#endregion //#region node_modules/three-stdlib/postprocessing/ShaderPass.js var __defProp$6 = Object.defineProperty; var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$6 = (obj, key, value) => { __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var ShaderPass = class extends Pass { constructor(shader, textureID = "tDiffuse") { super(); __publicField$6(this, "textureID"); __publicField$6(this, "uniforms"); __publicField$6(this, "material"); __publicField$6(this, "fsQuad"); this.textureID = textureID; if (shader instanceof ShaderMaterial) { this.uniforms = shader.uniforms; this.material = shader; } else { this.uniforms = UniformsUtils.clone(shader.uniforms); this.material = new ShaderMaterial({ defines: Object.assign({}, shader.defines), uniforms: this.uniforms, vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader }); } this.fsQuad = new FullScreenQuad(this.material); } render(renderer, writeBuffer, readBuffer) { if (this.uniforms[this.textureID]) this.uniforms[this.textureID].value = readBuffer.texture; this.fsQuad.material = this.material; if (this.renderToScreen) { renderer.setRenderTarget(null); this.fsQuad.render(renderer); } else { renderer.setRenderTarget(writeBuffer); if (this.clear) renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil); this.fsQuad.render(renderer); } } dispose() { this.fsQuad.dispose(); this.material.dispose(); } }; //#endregion //#region node_modules/three-stdlib/shaders/CopyShader.js var CopyShader = { uniforms: { tDiffuse: { value: null }, opacity: { value: 1 } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: ` uniform float opacity; uniform sampler2D tDiffuse; varying vec2 vUv; void main() { vec4 texel = texture2D( tDiffuse, vUv ); gl_FragColor = opacity * texel; } ` }; //#endregion //#region node_modules/three-stdlib/postprocessing/MaskPass.js var __defProp$5 = Object.defineProperty; var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$5 = (obj, key, value) => { __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var MaskPass = class extends Pass { constructor(scene, camera) { super(); __publicField$5(this, "scene"); __publicField$5(this, "camera"); __publicField$5(this, "inverse"); this.scene = scene; this.camera = camera; this.clear = true; this.needsSwap = false; this.inverse = false; } render(renderer, writeBuffer, readBuffer) { const context = renderer.getContext(); const state = renderer.state; state.buffers.color.setMask(false); state.buffers.depth.setMask(false); state.buffers.color.setLocked(true); state.buffers.depth.setLocked(true); let writeValue, clearValue; if (this.inverse) { writeValue = 0; clearValue = 1; } else { writeValue = 1; clearValue = 0; } state.buffers.stencil.setTest(true); state.buffers.stencil.setOp(context.REPLACE, context.REPLACE, context.REPLACE); state.buffers.stencil.setFunc(context.ALWAYS, writeValue, 4294967295); state.buffers.stencil.setClear(clearValue); state.buffers.stencil.setLocked(true); renderer.setRenderTarget(readBuffer); if (this.clear) renderer.clear(); renderer.render(this.scene, this.camera); renderer.setRenderTarget(writeBuffer); if (this.clear) renderer.clear(); renderer.render(this.scene, this.camera); state.buffers.color.setLocked(false); state.buffers.depth.setLocked(false); state.buffers.stencil.setLocked(false); state.buffers.stencil.setFunc(context.EQUAL, 1, 4294967295); state.buffers.stencil.setOp(context.KEEP, context.KEEP, context.KEEP); state.buffers.stencil.setLocked(true); } }; var ClearMaskPass = class extends Pass { constructor() { super(); this.needsSwap = false; } render(renderer) { renderer.state.buffers.stencil.setLocked(false); renderer.state.buffers.stencil.setTest(false); } }; //#endregion //#region node_modules/three-stdlib/postprocessing/EffectComposer.js var __defProp$4 = Object.defineProperty; var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$4 = (obj, key, value) => { __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var EffectComposer = class { constructor(renderer, renderTarget) { __publicField$4(this, "renderer"); __publicField$4(this, "_pixelRatio"); __publicField$4(this, "_width"); __publicField$4(this, "_height"); __publicField$4(this, "renderTarget1"); __publicField$4(this, "renderTarget2"); __publicField$4(this, "writeBuffer"); __publicField$4(this, "readBuffer"); __publicField$4(this, "renderToScreen"); __publicField$4(this, "passes", []); __publicField$4(this, "copyPass"); __publicField$4(this, "clock"); this.renderer = renderer; if (renderTarget === void 0) { const parameters = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat }; const size = renderer.getSize(new Vector2()); this._pixelRatio = renderer.getPixelRatio(); this._width = size.width; this._height = size.height; renderTarget = new WebGLRenderTarget(this._width * this._pixelRatio, this._height * this._pixelRatio, parameters); renderTarget.texture.name = "EffectComposer.rt1"; } else { this._pixelRatio = 1; this._width = renderTarget.width; this._height = renderTarget.height; } this.renderTarget1 = renderTarget; this.renderTarget2 = renderTarget.clone(); this.renderTarget2.texture.name = "EffectComposer.rt2"; this.writeBuffer = this.renderTarget1; this.readBuffer = this.renderTarget2; this.renderToScreen = true; if (CopyShader === void 0) console.error("THREE.EffectComposer relies on CopyShader"); if (ShaderPass === void 0) console.error("THREE.EffectComposer relies on ShaderPass"); this.copyPass = new ShaderPass(CopyShader); this.copyPass.material.blending = 0; this.clock = new Clock(); } swapBuffers() { const tmp = this.readBuffer; this.readBuffer = this.writeBuffer; this.writeBuffer = tmp; } addPass(pass) { this.passes.push(pass); pass.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio); } insertPass(pass, index) { this.passes.splice(index, 0, pass); pass.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio); } removePass(pass) { const index = this.passes.indexOf(pass); if (index !== -1) this.passes.splice(index, 1); } isLastEnabledPass(passIndex) { for (let i = passIndex + 1; i < this.passes.length; i++) if (this.passes[i].enabled) return false; return true; } render(deltaTime) { if (deltaTime === void 0) deltaTime = this.clock.getDelta(); const currentRenderTarget = this.renderer.getRenderTarget(); let maskActive = false; const il = this.passes.length; for (let i = 0; i < il; i++) { const pass = this.passes[i]; if (pass.enabled === false) continue; pass.renderToScreen = this.renderToScreen && this.isLastEnabledPass(i); pass.render(this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive); if (pass.needsSwap) { if (maskActive) { const context = this.renderer.getContext(); const stencil = this.renderer.state.buffers.stencil; stencil.setFunc(context.NOTEQUAL, 1, 4294967295); this.copyPass.render(this.renderer, this.writeBuffer, this.readBuffer, deltaTime); stencil.setFunc(context.EQUAL, 1, 4294967295); } this.swapBuffers(); } if (MaskPass !== void 0) { if (pass instanceof MaskPass) maskActive = true; else if (pass instanceof ClearMaskPass) maskActive = false; } } this.renderer.setRenderTarget(currentRenderTarget); } reset(renderTarget) { if (renderTarget === void 0) { const size = this.renderer.getSize(new Vector2()); this._pixelRatio = this.renderer.getPixelRatio(); this._width = size.width; this._height = size.height; renderTarget = this.renderTarget1.clone(); renderTarget.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio); } this.renderTarget1.dispose(); this.renderTarget2.dispose(); this.renderTarget1 = renderTarget; this.renderTarget2 = renderTarget.clone(); this.writeBuffer = this.renderTarget1; this.readBuffer = this.renderTarget2; } setSize(width, height) { this._width = width; this._height = height; const effectiveWidth = this._width * this._pixelRatio; const effectiveHeight = this._height * this._pixelRatio; this.renderTarget1.setSize(effectiveWidth, effectiveHeight); this.renderTarget2.setSize(effectiveWidth, effectiveHeight); for (let i = 0; i < this.passes.length; i++) this.passes[i].setSize(effectiveWidth, effectiveHeight); } setPixelRatio(pixelRatio) { this._pixelRatio = pixelRatio; this.setSize(this._width, this._height); } dispose() { this.renderTarget1.dispose(); this.renderTarget2.dispose(); this.copyPass.dispose(); } }; //#endregion //#region node_modules/three-stdlib/postprocessing/RenderPass.js var __defProp$3 = Object.defineProperty; var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$3 = (obj, key, value) => { __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var RenderPass = class extends Pass { constructor(scene, camera, overrideMaterial, clearColor, clearAlpha = 0) { super(); __publicField$3(this, "scene"); __publicField$3(this, "camera"); __publicField$3(this, "overrideMaterial"); __publicField$3(this, "clearColor"); __publicField$3(this, "clearAlpha"); __publicField$3(this, "clearDepth", false); __publicField$3(this, "_oldClearColor", new Color()); this.scene = scene; this.camera = camera; this.overrideMaterial = overrideMaterial; this.clearColor = clearColor; this.clearAlpha = clearAlpha; this.clear = true; this.needsSwap = false; } render(renderer, writeBuffer, readBuffer) { let oldAutoClear = renderer.autoClear; renderer.autoClear = false; let oldClearAlpha; let oldOverrideMaterial = null; if (this.overrideMaterial !== void 0) { oldOverrideMaterial = this.scene.overrideMaterial; this.scene.overrideMaterial = this.overrideMaterial; } if (this.clearColor) { renderer.getClearColor(this._oldClearColor); oldClearAlpha = renderer.getClearAlpha(); renderer.setClearColor(this.clearColor, this.clearAlpha); } if (this.clearDepth) renderer.clearDepth(); renderer.setRenderTarget(this.renderToScreen ? null : readBuffer); if (this.clear) renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil); renderer.render(this.scene, this.camera); if (this.clearColor) renderer.setClearColor(this._oldClearColor, oldClearAlpha); if (this.overrideMaterial !== void 0) this.scene.overrideMaterial = oldOverrideMaterial; renderer.autoClear = oldAutoClear; } }; //#endregion //#region node_modules/three-stdlib/_polyfill/LoaderUtils.js function decodeText$1(array) { if (typeof TextDecoder !== "undefined") return new TextDecoder().decode(array); let s = ""; for (let i = 0, il = array.length; i < il; i++) s += String.fromCharCode(array[i]); try { return decodeURIComponent(escape(s)); } catch (e) { return s; } } //#endregion //#region node_modules/three-stdlib/loaders/GLTFLoader.js var SRGBColorSpace$1 = "srgb"; var LinearSRGBColorSpace$1 = "srgb-linear"; var sRGBEncoding$1 = 3001; var LinearEncoding$1 = 3e3; var GLTFLoader = class extends Loader$1 { constructor(manager) { super(manager); this.dracoLoader = null; this.ktx2Loader = null; this.meshoptDecoder = null; this.pluginCallbacks = []; this.register(function(parser) { return new GLTFMaterialsClearcoatExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsDispersionExtension(parser); }); this.register(function(parser) { return new GLTFTextureBasisUExtension(parser); }); this.register(function(parser) { return new GLTFTextureWebPExtension(parser); }); this.register(function(parser) { return new GLTFTextureAVIFExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsSheenExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsTransmissionExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsVolumeExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsIorExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsEmissiveStrengthExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsSpecularExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsIridescenceExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsAnisotropyExtension(parser); }); this.register(function(parser) { return new GLTFMaterialsBumpExtension(parser); }); this.register(function(parser) { return new GLTFLightsExtension(parser); }); this.register(function(parser) { return new GLTFMeshoptCompression(parser); }); this.register(function(parser) { return new GLTFMeshGpuInstancing(parser); }); } load(url, onLoad, onProgress, onError) { const scope = this; let resourcePath; if (this.resourcePath !== "") resourcePath = this.resourcePath; else if (this.path !== "") { const relativeUrl = LoaderUtils.extractUrlBase(url); resourcePath = LoaderUtils.resolveURL(relativeUrl, this.path); } else resourcePath = LoaderUtils.extractUrlBase(url); this.manager.itemStart(url); const _onError = function(e) { if (onError) onError(e); else console.error(e); scope.manager.itemError(url); scope.manager.itemEnd(url); }; const loader = new FileLoader(this.manager); loader.setPath(this.path); loader.setResponseType("arraybuffer"); loader.setRequestHeader(this.requestHeader); loader.setWithCredentials(this.withCredentials); loader.load(url, function(data) { try { scope.parse(data, resourcePath, function(gltf) { onLoad(gltf); scope.manager.itemEnd(url); }, _onError); } catch (e) { _onError(e); } }, onProgress, _onError); } setDRACOLoader(dracoLoader) { this.dracoLoader = dracoLoader; return this; } setDDSLoader() { throw new Error("THREE.GLTFLoader: \"MSFT_texture_dds\" no longer supported. Please update to \"KHR_texture_basisu\"."); } setKTX2Loader(ktx2Loader) { this.ktx2Loader = ktx2Loader; return this; } setMeshoptDecoder(meshoptDecoder) { this.meshoptDecoder = meshoptDecoder; return this; } register(callback) { if (this.pluginCallbacks.indexOf(callback) === -1) this.pluginCallbacks.push(callback); return this; } unregister(callback) { if (this.pluginCallbacks.indexOf(callback) !== -1) this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1); return this; } parse(data, path, onLoad, onError) { let json; const extensions = {}; const plugins = {}; if (typeof data === "string") json = JSON.parse(data); else if (data instanceof ArrayBuffer) if (decodeText$1(new Uint8Array(data.slice(0, 4))) === BINARY_EXTENSION_HEADER_MAGIC) { try { extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data); } catch (error) { if (onError) onError(error); return; } json = JSON.parse(extensions[EXTENSIONS.KHR_BINARY_GLTF].content); } else json = JSON.parse(decodeText$1(new Uint8Array(data))); else json = data; if (json.asset === void 0 || json.asset.version[0] < 2) { if (onError) onError(/* @__PURE__ */ new Error("THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.")); return; } const parser = new GLTFParser(json, { path: path || this.resourcePath || "", crossOrigin: this.crossOrigin, requestHeader: this.requestHeader, manager: this.manager, ktx2Loader: this.ktx2Loader, meshoptDecoder: this.meshoptDecoder }); parser.fileLoader.setRequestHeader(this.requestHeader); for (let i = 0; i < this.pluginCallbacks.length; i++) { const plugin = this.pluginCallbacks[i](parser); if (!plugin.name) console.error("THREE.GLTFLoader: Invalid plugin found: missing name"); plugins[plugin.name] = plugin; extensions[plugin.name] = true; } if (json.extensionsUsed) for (let i = 0; i < json.extensionsUsed.length; ++i) { const extensionName = json.extensionsUsed[i]; const extensionsRequired = json.extensionsRequired || []; switch (extensionName) { case EXTENSIONS.KHR_MATERIALS_UNLIT: extensions[extensionName] = new GLTFMaterialsUnlitExtension(); break; case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION: extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader); break; case EXTENSIONS.KHR_TEXTURE_TRANSFORM: extensions[extensionName] = new GLTFTextureTransformExtension(); break; case EXTENSIONS.KHR_MESH_QUANTIZATION: extensions[extensionName] = new GLTFMeshQuantizationExtension(); break; default: if (extensionsRequired.indexOf(extensionName) >= 0 && plugins[extensionName] === void 0) console.warn("THREE.GLTFLoader: Unknown extension \"" + extensionName + "\"."); } } parser.setExtensions(extensions); parser.setPlugins(plugins); parser.parse(onLoad, onError); } parseAsync(data, path) { const scope = this; return new Promise(function(resolve, reject) { scope.parse(data, path, resolve, reject); }); } }; function GLTFRegistry() { let objects = {}; return { get: function(key) { return objects[key]; }, add: function(key, object) { objects[key] = object; }, remove: function(key) { delete objects[key]; }, removeAll: function() { objects = {}; } }; } var EXTENSIONS = { KHR_BINARY_GLTF: "KHR_binary_glTF", KHR_DRACO_MESH_COMPRESSION: "KHR_draco_mesh_compression", KHR_LIGHTS_PUNCTUAL: "KHR_lights_punctual", KHR_MATERIALS_CLEARCOAT: "KHR_materials_clearcoat", KHR_MATERIALS_DISPERSION: "KHR_materials_dispersion", KHR_MATERIALS_IOR: "KHR_materials_ior", KHR_MATERIALS_SHEEN: "KHR_materials_sheen", KHR_MATERIALS_SPECULAR: "KHR_materials_specular", KHR_MATERIALS_TRANSMISSION: "KHR_materials_transmission", KHR_MATERIALS_IRIDESCENCE: "KHR_materials_iridescence", KHR_MATERIALS_ANISOTROPY: "KHR_materials_anisotropy", KHR_MATERIALS_UNLIT: "KHR_materials_unlit", KHR_MATERIALS_VOLUME: "KHR_materials_volume", KHR_TEXTURE_BASISU: "KHR_texture_basisu", KHR_TEXTURE_TRANSFORM: "KHR_texture_transform", KHR_MESH_QUANTIZATION: "KHR_mesh_quantization", KHR_MATERIALS_EMISSIVE_STRENGTH: "KHR_materials_emissive_strength", EXT_MATERIALS_BUMP: "EXT_materials_bump", EXT_TEXTURE_WEBP: "EXT_texture_webp", EXT_TEXTURE_AVIF: "EXT_texture_avif", EXT_MESHOPT_COMPRESSION: "EXT_meshopt_compression", EXT_MESH_GPU_INSTANCING: "EXT_mesh_gpu_instancing" }; var GLTFLightsExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL; this.cache = { refs: {}, uses: {} }; } _markDefs() { const parser = this.parser; const nodeDefs = this.parser.json.nodes || []; for (let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) { const nodeDef = nodeDefs[nodeIndex]; if (nodeDef.extensions && nodeDef.extensions[this.name] && nodeDef.extensions[this.name].light !== void 0) parser._addNodeRef(this.cache, nodeDef.extensions[this.name].light); } } _loadLight(lightIndex) { const parser = this.parser; const cacheKey = "light:" + lightIndex; let dependency = parser.cache.get(cacheKey); if (dependency) return dependency; const json = parser.json; const lightDef = ((json.extensions && json.extensions[this.name] || {}).lights || [])[lightIndex]; let lightNode; const color = new Color(16777215); if (lightDef.color !== void 0) color.setRGB(lightDef.color[0], lightDef.color[1], lightDef.color[2], LinearSRGBColorSpace$1); const range = lightDef.range !== void 0 ? lightDef.range : 0; switch (lightDef.type) { case "directional": lightNode = new DirectionalLight(color); lightNode.target.position.set(0, 0, -1); lightNode.add(lightNode.target); break; case "point": lightNode = new PointLight(color); lightNode.distance = range; break; case "spot": lightNode = new SpotLight$1(color); lightNode.distance = range; lightDef.spot = lightDef.spot || {}; lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== void 0 ? lightDef.spot.innerConeAngle : 0; lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== void 0 ? lightDef.spot.outerConeAngle : Math.PI / 4; lightNode.angle = lightDef.spot.outerConeAngle; lightNode.penumbra = 1 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle; lightNode.target.position.set(0, 0, -1); lightNode.add(lightNode.target); break; default: throw new Error("THREE.GLTFLoader: Unexpected light type: " + lightDef.type); } lightNode.position.set(0, 0, 0); lightNode.decay = 2; assignExtrasToUserData(lightNode, lightDef); if (lightDef.intensity !== void 0) lightNode.intensity = lightDef.intensity; lightNode.name = parser.createUniqueName(lightDef.name || "light_" + lightIndex); dependency = Promise.resolve(lightNode); parser.cache.add(cacheKey, dependency); return dependency; } getDependency(type, index) { if (type !== "light") return; return this._loadLight(index); } createNodeAttachment(nodeIndex) { const self2 = this; const parser = this.parser; const nodeDef = parser.json.nodes[nodeIndex]; const lightIndex = (nodeDef.extensions && nodeDef.extensions[this.name] || {}).light; if (lightIndex === void 0) return null; return this._loadLight(lightIndex).then(function(light) { return parser._getNodeRef(self2.cache, lightIndex, light); }); } }; var GLTFMaterialsUnlitExtension = class { constructor() { this.name = EXTENSIONS.KHR_MATERIALS_UNLIT; } getMaterialType() { return MeshBasicMaterial; } extendParams(materialParams, materialDef, parser) { const pending = []; materialParams.color = new Color(1, 1, 1); materialParams.opacity = 1; const metallicRoughness = materialDef.pbrMetallicRoughness; if (metallicRoughness) { if (Array.isArray(metallicRoughness.baseColorFactor)) { const array = metallicRoughness.baseColorFactor; materialParams.color.setRGB(array[0], array[1], array[2], LinearSRGBColorSpace$1); materialParams.opacity = array[3]; } if (metallicRoughness.baseColorTexture !== void 0) pending.push(parser.assignTexture(materialParams, "map", metallicRoughness.baseColorTexture, SRGBColorSpace$1)); } return Promise.all(pending); } }; var GLTFMaterialsEmissiveStrengthExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH; } extendMaterialParams(materialIndex, materialParams) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const emissiveStrength = materialDef.extensions[this.name].emissiveStrength; if (emissiveStrength !== void 0) materialParams.emissiveIntensity = emissiveStrength; return Promise.resolve(); } }; var GLTFMaterialsClearcoatExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; if (extension.clearcoatFactor !== void 0) materialParams.clearcoat = extension.clearcoatFactor; if (extension.clearcoatTexture !== void 0) pending.push(parser.assignTexture(materialParams, "clearcoatMap", extension.clearcoatTexture)); if (extension.clearcoatRoughnessFactor !== void 0) materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor; if (extension.clearcoatRoughnessTexture !== void 0) pending.push(parser.assignTexture(materialParams, "clearcoatRoughnessMap", extension.clearcoatRoughnessTexture)); if (extension.clearcoatNormalTexture !== void 0) { pending.push(parser.assignTexture(materialParams, "clearcoatNormalMap", extension.clearcoatNormalTexture)); if (extension.clearcoatNormalTexture.scale !== void 0) { const scale = extension.clearcoatNormalTexture.scale; materialParams.clearcoatNormalScale = new Vector2(scale, scale); } } return Promise.all(pending); } }; var GLTFMaterialsDispersionExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_DISPERSION; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const extension = materialDef.extensions[this.name]; materialParams.dispersion = extension.dispersion !== void 0 ? extension.dispersion : 0; return Promise.resolve(); } }; var GLTFMaterialsIridescenceExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_IRIDESCENCE; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; if (extension.iridescenceFactor !== void 0) materialParams.iridescence = extension.iridescenceFactor; if (extension.iridescenceTexture !== void 0) pending.push(parser.assignTexture(materialParams, "iridescenceMap", extension.iridescenceTexture)); if (extension.iridescenceIor !== void 0) materialParams.iridescenceIOR = extension.iridescenceIor; if (materialParams.iridescenceThicknessRange === void 0) materialParams.iridescenceThicknessRange = [100, 400]; if (extension.iridescenceThicknessMinimum !== void 0) materialParams.iridescenceThicknessRange[0] = extension.iridescenceThicknessMinimum; if (extension.iridescenceThicknessMaximum !== void 0) materialParams.iridescenceThicknessRange[1] = extension.iridescenceThicknessMaximum; if (extension.iridescenceThicknessTexture !== void 0) pending.push(parser.assignTexture(materialParams, "iridescenceThicknessMap", extension.iridescenceThicknessTexture)); return Promise.all(pending); } }; var GLTFMaterialsSheenExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_SHEEN; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; materialParams.sheenColor = new Color(0, 0, 0); materialParams.sheenRoughness = 0; materialParams.sheen = 1; const extension = materialDef.extensions[this.name]; if (extension.sheenColorFactor !== void 0) { const colorFactor = extension.sheenColorFactor; materialParams.sheenColor.setRGB(colorFactor[0], colorFactor[1], colorFactor[2], LinearSRGBColorSpace$1); } if (extension.sheenRoughnessFactor !== void 0) materialParams.sheenRoughness = extension.sheenRoughnessFactor; if (extension.sheenColorTexture !== void 0) pending.push(parser.assignTexture(materialParams, "sheenColorMap", extension.sheenColorTexture, SRGBColorSpace$1)); if (extension.sheenRoughnessTexture !== void 0) pending.push(parser.assignTexture(materialParams, "sheenRoughnessMap", extension.sheenRoughnessTexture)); return Promise.all(pending); } }; var GLTFMaterialsTransmissionExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; if (extension.transmissionFactor !== void 0) materialParams.transmission = extension.transmissionFactor; if (extension.transmissionTexture !== void 0) pending.push(parser.assignTexture(materialParams, "transmissionMap", extension.transmissionTexture)); return Promise.all(pending); } }; var GLTFMaterialsVolumeExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_VOLUME; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; materialParams.thickness = extension.thicknessFactor !== void 0 ? extension.thicknessFactor : 0; if (extension.thicknessTexture !== void 0) pending.push(parser.assignTexture(materialParams, "thicknessMap", extension.thicknessTexture)); materialParams.attenuationDistance = extension.attenuationDistance || Infinity; const colorArray = extension.attenuationColor || [ 1, 1, 1 ]; materialParams.attenuationColor = new Color().setRGB(colorArray[0], colorArray[1], colorArray[2], LinearSRGBColorSpace$1); return Promise.all(pending); } }; var GLTFMaterialsIorExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_IOR; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const extension = materialDef.extensions[this.name]; materialParams.ior = extension.ior !== void 0 ? extension.ior : 1.5; return Promise.resolve(); } }; var GLTFMaterialsSpecularExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; materialParams.specularIntensity = extension.specularFactor !== void 0 ? extension.specularFactor : 1; if (extension.specularTexture !== void 0) pending.push(parser.assignTexture(materialParams, "specularIntensityMap", extension.specularTexture)); const colorArray = extension.specularColorFactor || [ 1, 1, 1 ]; materialParams.specularColor = new Color().setRGB(colorArray[0], colorArray[1], colorArray[2], LinearSRGBColorSpace$1); if (extension.specularColorTexture !== void 0) pending.push(parser.assignTexture(materialParams, "specularColorMap", extension.specularColorTexture, SRGBColorSpace$1)); return Promise.all(pending); } }; var GLTFMaterialsBumpExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.EXT_MATERIALS_BUMP; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; materialParams.bumpScale = extension.bumpFactor !== void 0 ? extension.bumpFactor : 1; if (extension.bumpTexture !== void 0) pending.push(parser.assignTexture(materialParams, "bumpMap", extension.bumpTexture)); return Promise.all(pending); } }; var GLTFMaterialsAnisotropyExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_MATERIALS_ANISOTROPY; } getMaterialType(materialIndex) { const materialDef = this.parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; return MeshPhysicalMaterial; } extendMaterialParams(materialIndex, materialParams) { const parser = this.parser; const materialDef = parser.json.materials[materialIndex]; if (!materialDef.extensions || !materialDef.extensions[this.name]) return Promise.resolve(); const pending = []; const extension = materialDef.extensions[this.name]; if (extension.anisotropyStrength !== void 0) materialParams.anisotropy = extension.anisotropyStrength; if (extension.anisotropyRotation !== void 0) materialParams.anisotropyRotation = extension.anisotropyRotation; if (extension.anisotropyTexture !== void 0) pending.push(parser.assignTexture(materialParams, "anisotropyMap", extension.anisotropyTexture)); return Promise.all(pending); } }; var GLTFTextureBasisUExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.KHR_TEXTURE_BASISU; } loadTexture(textureIndex) { const parser = this.parser; const json = parser.json; const textureDef = json.textures[textureIndex]; if (!textureDef.extensions || !textureDef.extensions[this.name]) return null; const extension = textureDef.extensions[this.name]; const loader = parser.options.ktx2Loader; if (!loader) if (json.extensionsRequired && json.extensionsRequired.indexOf(this.name) >= 0) throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures"); else return null; return parser.loadTextureImage(textureIndex, extension.source, loader); } }; var GLTFTextureWebPExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.EXT_TEXTURE_WEBP; this.isSupported = null; } loadTexture(textureIndex) { const name = this.name; const parser = this.parser; const json = parser.json; const textureDef = json.textures[textureIndex]; if (!textureDef.extensions || !textureDef.extensions[name]) return null; const extension = textureDef.extensions[name]; const source = json.images[extension.source]; let loader = parser.textureLoader; if (source.uri) { const handler = parser.options.manager.getHandler(source.uri); if (handler !== null) loader = handler; } return this.detectSupport().then(function(isSupported) { if (isSupported) return parser.loadTextureImage(textureIndex, extension.source, loader); if (json.extensionsRequired && json.extensionsRequired.indexOf(name) >= 0) throw new Error("THREE.GLTFLoader: WebP required by asset but unsupported."); return parser.loadTexture(textureIndex); }); } detectSupport() { if (!this.isSupported) this.isSupported = new Promise(function(resolve) { const image = new Image(); image.src = "data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA"; image.onload = image.onerror = function() { resolve(image.height === 1); }; }); return this.isSupported; } }; var GLTFTextureAVIFExtension = class { constructor(parser) { this.parser = parser; this.name = EXTENSIONS.EXT_TEXTURE_AVIF; this.isSupported = null; } loadTexture(textureIndex) { const name = this.name; const parser = this.parser; const json = parser.json; const textureDef = json.textures[textureIndex]; if (!textureDef.extensions || !textureDef.extensions[name]) return null; const extension = textureDef.extensions[name]; const source = json.images[extension.source]; let loader = parser.textureLoader; if (source.uri) { const handler = parser.options.manager.getHandler(source.uri); if (handler !== null) loader = handler; } return this.detectSupport().then(function(isSupported) { if (isSupported) return parser.loadTextureImage(textureIndex, extension.source, loader); if (json.extensionsRequired && json.extensionsRequired.indexOf(name) >= 0) throw new Error("THREE.GLTFLoader: AVIF required by asset but unsupported."); return parser.loadTexture(textureIndex); }); } detectSupport() { if (!this.isSupported) this.isSupported = new Promise(function(resolve) { const image = new Image(); image.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABcAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB9tZGF0EgAKCBgABogQEDQgMgkQAAAAB8dSLfI="; image.onload = image.onerror = function() { resolve(image.height === 1); }; }); return this.isSupported; } }; var GLTFMeshoptCompression = class { constructor(parser) { this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION; this.parser = parser; } loadBufferView(index) { const json = this.parser.json; const bufferView = json.bufferViews[index]; if (bufferView.extensions && bufferView.extensions[this.name]) { const extensionDef = bufferView.extensions[this.name]; const buffer = this.parser.getDependency("buffer", extensionDef.buffer); const decoder = this.parser.options.meshoptDecoder; if (!decoder || !decoder.supported) if (json.extensionsRequired && json.extensionsRequired.indexOf(this.name) >= 0) throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files"); else return null; return buffer.then(function(res) { const byteOffset = extensionDef.byteOffset || 0; const byteLength = extensionDef.byteLength || 0; const count = extensionDef.count; const stride = extensionDef.byteStride; const source = new Uint8Array(res, byteOffset, byteLength); if (decoder.decodeGltfBufferAsync) return decoder.decodeGltfBufferAsync(count, stride, source, extensionDef.mode, extensionDef.filter).then(function(res2) { return res2.buffer; }); else return decoder.ready.then(function() { const result = new ArrayBuffer(count * stride); decoder.decodeGltfBuffer(new Uint8Array(result), count, stride, source, extensionDef.mode, extensionDef.filter); return result; }); }); } else return null; } }; var GLTFMeshGpuInstancing = class { constructor(parser) { this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING; this.parser = parser; } createNodeMesh(nodeIndex) { const json = this.parser.json; const nodeDef = json.nodes[nodeIndex]; if (!nodeDef.extensions || !nodeDef.extensions[this.name] || nodeDef.mesh === void 0) return null; const meshDef = json.meshes[nodeDef.mesh]; for (const primitive of meshDef.primitives) if (primitive.mode !== WEBGL_CONSTANTS.TRIANGLES && primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_STRIP && primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_FAN && primitive.mode !== void 0) return null; const attributesDef = nodeDef.extensions[this.name].attributes; const pending = []; const attributes = {}; for (const key in attributesDef) pending.push(this.parser.getDependency("accessor", attributesDef[key]).then((accessor) => { attributes[key] = accessor; return attributes[key]; })); if (pending.length < 1) return null; pending.push(this.parser.createNodeMesh(nodeIndex)); return Promise.all(pending).then((results) => { const nodeObject = results.pop(); const meshes = nodeObject.isGroup ? nodeObject.children : [nodeObject]; const count = results[0].count; const instancedMeshes = []; for (const mesh of meshes) { const m = new Matrix4(); const p = new Vector3(); const q = new Quaternion(); const s = new Vector3(1, 1, 1); const instancedMesh = new InstancedMesh(mesh.geometry, mesh.material, count); for (let i = 0; i < count; i++) { if (attributes.TRANSLATION) p.fromBufferAttribute(attributes.TRANSLATION, i); if (attributes.ROTATION) q.fromBufferAttribute(attributes.ROTATION, i); if (attributes.SCALE) s.fromBufferAttribute(attributes.SCALE, i); instancedMesh.setMatrixAt(i, m.compose(p, q, s)); } for (const attributeName in attributes) if (attributeName === "_COLOR_0") { const attr = attributes[attributeName]; instancedMesh.instanceColor = new InstancedBufferAttribute(attr.array, attr.itemSize, attr.normalized); } else if (attributeName !== "TRANSLATION" && attributeName !== "ROTATION" && attributeName !== "SCALE") mesh.geometry.setAttribute(attributeName, attributes[attributeName]); Object3D.prototype.copy.call(instancedMesh, mesh); this.parser.assignFinalMaterial(instancedMesh); instancedMeshes.push(instancedMesh); } if (nodeObject.isGroup) { nodeObject.clear(); nodeObject.add(...instancedMeshes); return nodeObject; } return instancedMeshes[0]; }); } }; var BINARY_EXTENSION_HEADER_MAGIC = "glTF"; var BINARY_EXTENSION_HEADER_LENGTH = 12; var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 1313821514, BIN: 5130562 }; var GLTFBinaryExtension = class { constructor(data) { this.name = EXTENSIONS.KHR_BINARY_GLTF; this.content = null; this.body = null; const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH); this.header = { magic: decodeText$1(new Uint8Array(data.slice(0, 4))), version: headerView.getUint32(4, true), length: headerView.getUint32(8, true) }; if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header."); else if (this.header.version < 2) throw new Error("THREE.GLTFLoader: Legacy binary file detected."); const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH; const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH); let chunkIndex = 0; while (chunkIndex < chunkContentsLength) { const chunkLength = chunkView.getUint32(chunkIndex, true); chunkIndex += 4; const chunkType = chunkView.getUint32(chunkIndex, true); chunkIndex += 4; if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) { const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength); this.content = decodeText$1(contentArray); } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) { const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; this.body = data.slice(byteOffset, byteOffset + chunkLength); } chunkIndex += chunkLength; } if (this.content === null) throw new Error("THREE.GLTFLoader: JSON content not found."); } }; var GLTFDracoMeshCompressionExtension = class { constructor(json, dracoLoader) { if (!dracoLoader) throw new Error("THREE.GLTFLoader: No DRACOLoader instance provided."); this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; this.json = json; this.dracoLoader = dracoLoader; this.dracoLoader.preload(); } decodePrimitive(primitive, parser) { const json = this.json; const dracoLoader = this.dracoLoader; const bufferViewIndex = primitive.extensions[this.name].bufferView; const gltfAttributeMap = primitive.extensions[this.name].attributes; const threeAttributeMap = {}; const attributeNormalizedMap = {}; const attributeTypeMap = {}; for (const attributeName in gltfAttributeMap) { const threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); threeAttributeMap[threeAttributeName] = gltfAttributeMap[attributeName]; } for (const attributeName in primitive.attributes) { const threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); if (gltfAttributeMap[attributeName] !== void 0) { const accessorDef = json.accessors[primitive.attributes[attributeName]]; attributeTypeMap[threeAttributeName] = WEBGL_COMPONENT_TYPES[accessorDef.componentType].name; attributeNormalizedMap[threeAttributeName] = accessorDef.normalized === true; } } return parser.getDependency("bufferView", bufferViewIndex).then(function(bufferView) { return new Promise(function(resolve, reject) { dracoLoader.decodeDracoFile(bufferView, function(geometry) { for (const attributeName in geometry.attributes) { const attribute = geometry.attributes[attributeName]; const normalized = attributeNormalizedMap[attributeName]; if (normalized !== void 0) attribute.normalized = normalized; } resolve(geometry); }, threeAttributeMap, attributeTypeMap, LinearSRGBColorSpace$1, reject); }); }); } }; var GLTFTextureTransformExtension = class { constructor() { this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM; } extendTexture(texture, transform) { if ((transform.texCoord === void 0 || transform.texCoord === texture.channel) && transform.offset === void 0 && transform.rotation === void 0 && transform.scale === void 0) return texture; texture = texture.clone(); if (transform.texCoord !== void 0) texture.channel = transform.texCoord; if (transform.offset !== void 0) texture.offset.fromArray(transform.offset); if (transform.rotation !== void 0) texture.rotation = transform.rotation; if (transform.scale !== void 0) texture.repeat.fromArray(transform.scale); texture.needsUpdate = true; return texture; } }; var GLTFMeshQuantizationExtension = class { constructor() { this.name = EXTENSIONS.KHR_MESH_QUANTIZATION; } }; var GLTFCubicSplineInterpolant = class extends Interpolant { constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { super(parameterPositions, sampleValues, sampleSize, resultBuffer); } copySampleValue_(index) { const result = this.resultBuffer, values = this.sampleValues, valueSize = this.valueSize, offset = index * valueSize * 3 + valueSize; for (let i = 0; i !== valueSize; i++) result[i] = values[offset + i]; return result; } interpolate_(i1, t0, t, t1) { const result = this.resultBuffer; const values = this.sampleValues; const stride = this.valueSize; const stride2 = stride * 2; const stride3 = stride * 3; const td = t1 - t0; const p = (t - t0) / td; const pp = p * p; const ppp = pp * p; const offset1 = i1 * stride3; const offset0 = offset1 - stride3; const s2 = -2 * ppp + 3 * pp; const s3 = ppp - pp; const s0 = 1 - s2; const s1 = s3 - pp + p; for (let i = 0; i !== stride; i++) { const p0 = values[offset0 + i + stride]; const m0 = values[offset0 + i + stride2] * td; const p1 = values[offset1 + i + stride]; const m1 = values[offset1 + i] * td; result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1; } return result; } }; var _q = /* @__PURE__ */ new Quaternion(); var GLTFCubicSplineQuaternionInterpolant = class extends GLTFCubicSplineInterpolant { interpolate_(i1, t0, t, t1) { const result = super.interpolate_(i1, t0, t, t1); _q.fromArray(result).normalize().toArray(result); return result; } }; var WEBGL_CONSTANTS = { FLOAT: 5126, FLOAT_MAT3: 35675, FLOAT_MAT4: 35676, FLOAT_VEC2: 35664, FLOAT_VEC3: 35665, FLOAT_VEC4: 35666, LINEAR: 9729, REPEAT: 10497, SAMPLER_2D: 35678, POINTS: 0, LINES: 1, LINE_LOOP: 2, LINE_STRIP: 3, TRIANGLES: 4, TRIANGLE_STRIP: 5, TRIANGLE_FAN: 6, UNSIGNED_BYTE: 5121, UNSIGNED_SHORT: 5123 }; var WEBGL_COMPONENT_TYPES = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }; var WEBGL_FILTERS = { 9728: NearestFilter, 9729: LinearFilter, 9984: NearestMipmapNearestFilter, 9985: LinearMipmapNearestFilter, 9986: NearestMipmapLinearFilter, 9987: LinearMipmapLinearFilter }; var WEBGL_WRAPPINGS = { 33071: ClampToEdgeWrapping, 33648: MirroredRepeatWrapping, 10497: RepeatWrapping }; var WEBGL_TYPE_SIZES = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }; var ATTRIBUTES = { POSITION: "position", NORMAL: "normal", TANGENT: "tangent", ...version$2 >= 152 ? { TEXCOORD_0: "uv", TEXCOORD_1: "uv1", TEXCOORD_2: "uv2", TEXCOORD_3: "uv3" } : { TEXCOORD_0: "uv", TEXCOORD_1: "uv2" }, COLOR_0: "color", WEIGHTS_0: "skinWeight", JOINTS_0: "skinIndex" }; var PATH_PROPERTIES = { scale: "scale", translation: "position", rotation: "quaternion", weights: "morphTargetInfluences" }; var INTERPOLATION = { CUBICSPLINE: void 0, LINEAR: InterpolateLinear, STEP: InterpolateDiscrete }; var ALPHA_MODES = { OPAQUE: "OPAQUE", MASK: "MASK", BLEND: "BLEND" }; function createDefaultMaterial(cache) { if (cache["DefaultMaterial"] === void 0) cache["DefaultMaterial"] = new MeshStandardMaterial({ color: 16777215, emissive: 0, metalness: 1, roughness: 1, transparent: false, depthTest: true, side: 0 }); return cache["DefaultMaterial"]; } function addUnknownExtensionsToUserData(knownExtensions, object, objectDef) { for (const name in objectDef.extensions) if (knownExtensions[name] === void 0) { object.userData.gltfExtensions = object.userData.gltfExtensions || {}; object.userData.gltfExtensions[name] = objectDef.extensions[name]; } } function assignExtrasToUserData(object, gltfDef) { if (gltfDef.extras !== void 0) if (typeof gltfDef.extras === "object") Object.assign(object.userData, gltfDef.extras); else console.warn("THREE.GLTFLoader: Ignoring primitive type .extras, " + gltfDef.extras); } function addMorphTargets(geometry, targets, parser) { let hasMorphPosition = false; let hasMorphNormal = false; let hasMorphColor = false; for (let i = 0, il = targets.length; i < il; i++) { const target = targets[i]; if (target.POSITION !== void 0) hasMorphPosition = true; if (target.NORMAL !== void 0) hasMorphNormal = true; if (target.COLOR_0 !== void 0) hasMorphColor = true; if (hasMorphPosition && hasMorphNormal && hasMorphColor) break; } if (!hasMorphPosition && !hasMorphNormal && !hasMorphColor) return Promise.resolve(geometry); const pendingPositionAccessors = []; const pendingNormalAccessors = []; const pendingColorAccessors = []; for (let i = 0, il = targets.length; i < il; i++) { const target = targets[i]; if (hasMorphPosition) { const pendingAccessor = target.POSITION !== void 0 ? parser.getDependency("accessor", target.POSITION) : geometry.attributes.position; pendingPositionAccessors.push(pendingAccessor); } if (hasMorphNormal) { const pendingAccessor = target.NORMAL !== void 0 ? parser.getDependency("accessor", target.NORMAL) : geometry.attributes.normal; pendingNormalAccessors.push(pendingAccessor); } if (hasMorphColor) { const pendingAccessor = target.COLOR_0 !== void 0 ? parser.getDependency("accessor", target.COLOR_0) : geometry.attributes.color; pendingColorAccessors.push(pendingAccessor); } } return Promise.all([ Promise.all(pendingPositionAccessors), Promise.all(pendingNormalAccessors), Promise.all(pendingColorAccessors) ]).then(function(accessors) { const morphPositions = accessors[0]; const morphNormals = accessors[1]; const morphColors = accessors[2]; if (hasMorphPosition) geometry.morphAttributes.position = morphPositions; if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals; if (hasMorphColor) geometry.morphAttributes.color = morphColors; geometry.morphTargetsRelative = true; return geometry; }); } function updateMorphTargets(mesh, meshDef) { mesh.updateMorphTargets(); if (meshDef.weights !== void 0) for (let i = 0, il = meshDef.weights.length; i < il; i++) mesh.morphTargetInfluences[i] = meshDef.weights[i]; if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) { const targetNames = meshDef.extras.targetNames; if (mesh.morphTargetInfluences.length === targetNames.length) { mesh.morphTargetDictionary = {}; for (let i = 0, il = targetNames.length; i < il; i++) mesh.morphTargetDictionary[targetNames[i]] = i; } else console.warn("THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names."); } } function createPrimitiveKey(primitiveDef) { let geometryKey; const dracoExtension = primitiveDef.extensions && primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]; if (dracoExtension) geometryKey = "draco:" + dracoExtension.bufferView + ":" + dracoExtension.indices + ":" + createAttributesKey(dracoExtension.attributes); else geometryKey = primitiveDef.indices + ":" + createAttributesKey(primitiveDef.attributes) + ":" + primitiveDef.mode; if (primitiveDef.targets !== void 0) for (let i = 0, il = primitiveDef.targets.length; i < il; i++) geometryKey += ":" + createAttributesKey(primitiveDef.targets[i]); return geometryKey; } function createAttributesKey(attributes) { let attributesKey = ""; const keys = Object.keys(attributes).sort(); for (let i = 0, il = keys.length; i < il; i++) attributesKey += keys[i] + ":" + attributes[keys[i]] + ";"; return attributesKey; } function getNormalizedComponentScale(constructor) { switch (constructor) { case Int8Array: return 1 / 127; case Uint8Array: return 1 / 255; case Int16Array: return 1 / 32767; case Uint16Array: return 1 / 65535; default: throw new Error("THREE.GLTFLoader: Unsupported normalized accessor component type."); } } function getImageURIMimeType(uri) { if (uri.search(/\.jpe?g($|\?)/i) > 0 || uri.search(/^data\:image\/jpeg/) === 0) return "image/jpeg"; if (uri.search(/\.webp($|\?)/i) > 0 || uri.search(/^data\:image\/webp/) === 0) return "image/webp"; return "image/png"; } var _identityMatrix = /* @__PURE__ */ new Matrix4(); var GLTFParser = class { constructor(json = {}, options = {}) { this.json = json; this.extensions = {}; this.plugins = {}; this.options = options; this.cache = new GLTFRegistry(); this.associations = /* @__PURE__ */ new Map(); this.primitiveCache = {}; this.nodeCache = {}; this.meshCache = { refs: {}, uses: {} }; this.cameraCache = { refs: {}, uses: {} }; this.lightCache = { refs: {}, uses: {} }; this.sourceCache = {}; this.textureCache = {}; this.nodeNamesUsed = {}; let isSafari = false; let isFirefox = false; let firefoxVersion = -1; if (typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined") { isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) === true; isFirefox = navigator.userAgent.indexOf("Firefox") > -1; firefoxVersion = isFirefox ? navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1] : -1; } if (typeof createImageBitmap === "undefined" || isSafari || isFirefox && firefoxVersion < 98) this.textureLoader = new TextureLoader(this.options.manager); else this.textureLoader = new ImageBitmapLoader(this.options.manager); this.textureLoader.setCrossOrigin(this.options.crossOrigin); this.textureLoader.setRequestHeader(this.options.requestHeader); this.fileLoader = new FileLoader(this.options.manager); this.fileLoader.setResponseType("arraybuffer"); if (this.options.crossOrigin === "use-credentials") this.fileLoader.setWithCredentials(true); } setExtensions(extensions) { this.extensions = extensions; } setPlugins(plugins) { this.plugins = plugins; } parse(onLoad, onError) { const parser = this; const json = this.json; const extensions = this.extensions; this.cache.removeAll(); this.nodeCache = {}; this._invokeAll(function(ext) { return ext._markDefs && ext._markDefs(); }); Promise.all(this._invokeAll(function(ext) { return ext.beforeRoot && ext.beforeRoot(); })).then(function() { return Promise.all([ parser.getDependencies("scene"), parser.getDependencies("animation"), parser.getDependencies("camera") ]); }).then(function(dependencies) { const result = { scene: dependencies[0][json.scene || 0], scenes: dependencies[0], animations: dependencies[1], cameras: dependencies[2], asset: json.asset, parser, userData: {} }; addUnknownExtensionsToUserData(extensions, result, json); assignExtrasToUserData(result, json); return Promise.all(parser._invokeAll(function(ext) { return ext.afterRoot && ext.afterRoot(result); })).then(function() { for (const scene of result.scenes) scene.updateMatrixWorld(); onLoad(result); }); }).catch(onError); } /** * Marks the special nodes/meshes in json for efficient parse. */ _markDefs() { const nodeDefs = this.json.nodes || []; const skinDefs = this.json.skins || []; const meshDefs = this.json.meshes || []; for (let skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) { const joints = skinDefs[skinIndex].joints; for (let i = 0, il = joints.length; i < il; i++) nodeDefs[joints[i]].isBone = true; } for (let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) { const nodeDef = nodeDefs[nodeIndex]; if (nodeDef.mesh !== void 0) { this._addNodeRef(this.meshCache, nodeDef.mesh); if (nodeDef.skin !== void 0) meshDefs[nodeDef.mesh].isSkinnedMesh = true; } if (nodeDef.camera !== void 0) this._addNodeRef(this.cameraCache, nodeDef.camera); } } /** * Counts references to shared node / Object3D resources. These resources * can be reused, or "instantiated", at multiple nodes in the scene * hierarchy. Mesh, Camera, and Light instances are instantiated and must * be marked. Non-scenegraph resources (like Materials, Geometries, and * Textures) can be reused directly and are not marked here. * * Example: CesiumMilkTruck sample model reuses "Wheel" meshes. */ _addNodeRef(cache, index) { if (index === void 0) return; if (cache.refs[index] === void 0) cache.refs[index] = cache.uses[index] = 0; cache.refs[index]++; } /** Returns a reference to a shared resource, cloning it if necessary. */ _getNodeRef(cache, index, object) { if (cache.refs[index] <= 1) return object; const ref = object.clone(); const updateMappings = (original, clone) => { const mappings = this.associations.get(original); if (mappings != null) this.associations.set(clone, mappings); for (const [i, child] of original.children.entries()) updateMappings(child, clone.children[i]); }; updateMappings(object, ref); ref.name += "_instance_" + cache.uses[index]++; return ref; } _invokeOne(func) { const extensions = Object.values(this.plugins); extensions.push(this); for (let i = 0; i < extensions.length; i++) { const result = func(extensions[i]); if (result) return result; } return null; } _invokeAll(func) { const extensions = Object.values(this.plugins); extensions.unshift(this); const pending = []; for (let i = 0; i < extensions.length; i++) { const result = func(extensions[i]); if (result) pending.push(result); } return pending; } /** * Requests the specified dependency asynchronously, with caching. * @param {string} type * @param {number} index * @return {Promise} */ getDependency(type, index) { const cacheKey = type + ":" + index; let dependency = this.cache.get(cacheKey); if (!dependency) { switch (type) { case "scene": dependency = this.loadScene(index); break; case "node": dependency = this._invokeOne(function(ext) { return ext.loadNode && ext.loadNode(index); }); break; case "mesh": dependency = this._invokeOne(function(ext) { return ext.loadMesh && ext.loadMesh(index); }); break; case "accessor": dependency = this.loadAccessor(index); break; case "bufferView": dependency = this._invokeOne(function(ext) { return ext.loadBufferView && ext.loadBufferView(index); }); break; case "buffer": dependency = this.loadBuffer(index); break; case "material": dependency = this._invokeOne(function(ext) { return ext.loadMaterial && ext.loadMaterial(index); }); break; case "texture": dependency = this._invokeOne(function(ext) { return ext.loadTexture && ext.loadTexture(index); }); break; case "skin": dependency = this.loadSkin(index); break; case "animation": dependency = this._invokeOne(function(ext) { return ext.loadAnimation && ext.loadAnimation(index); }); break; case "camera": dependency = this.loadCamera(index); break; default: dependency = this._invokeOne(function(ext) { return ext != this && ext.getDependency && ext.getDependency(type, index); }); if (!dependency) throw new Error("Unknown type: " + type); break; } this.cache.add(cacheKey, dependency); } return dependency; } /** * Requests all dependencies of the specified type asynchronously, with caching. * @param {string} type * @return {Promise>} */ getDependencies(type) { let dependencies = this.cache.get(type); if (!dependencies) { const parser = this; const defs = this.json[type + (type === "mesh" ? "es" : "s")] || []; dependencies = Promise.all(defs.map(function(def, index) { return parser.getDependency(type, index); })); this.cache.add(type, dependencies); } return dependencies; } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views * @param {number} bufferIndex * @return {Promise} */ loadBuffer(bufferIndex) { const bufferDef = this.json.buffers[bufferIndex]; const loader = this.fileLoader; if (bufferDef.type && bufferDef.type !== "arraybuffer") throw new Error("THREE.GLTFLoader: " + bufferDef.type + " buffer type is not supported."); if (bufferDef.uri === void 0 && bufferIndex === 0) return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body); const options = this.options; return new Promise(function(resolve, reject) { loader.load(LoaderUtils.resolveURL(bufferDef.uri, options.path), resolve, void 0, function() { reject(/* @__PURE__ */ new Error("THREE.GLTFLoader: Failed to load buffer \"" + bufferDef.uri + "\".")); }); }); } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views * @param {number} bufferViewIndex * @return {Promise} */ loadBufferView(bufferViewIndex) { const bufferViewDef = this.json.bufferViews[bufferViewIndex]; return this.getDependency("buffer", bufferViewDef.buffer).then(function(buffer) { const byteLength = bufferViewDef.byteLength || 0; const byteOffset = bufferViewDef.byteOffset || 0; return buffer.slice(byteOffset, byteOffset + byteLength); }); } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors * @param {number} accessorIndex * @return {Promise} */ loadAccessor(accessorIndex) { const parser = this; const json = this.json; const accessorDef = this.json.accessors[accessorIndex]; if (accessorDef.bufferView === void 0 && accessorDef.sparse === void 0) { const itemSize = WEBGL_TYPE_SIZES[accessorDef.type]; const TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; const normalized = accessorDef.normalized === true; const array = new TypedArray(accessorDef.count * itemSize); return Promise.resolve(new BufferAttribute(array, itemSize, normalized)); } const pendingBufferViews = []; if (accessorDef.bufferView !== void 0) pendingBufferViews.push(this.getDependency("bufferView", accessorDef.bufferView)); else pendingBufferViews.push(null); if (accessorDef.sparse !== void 0) { pendingBufferViews.push(this.getDependency("bufferView", accessorDef.sparse.indices.bufferView)); pendingBufferViews.push(this.getDependency("bufferView", accessorDef.sparse.values.bufferView)); } return Promise.all(pendingBufferViews).then(function(bufferViews) { const bufferView = bufferViews[0]; const itemSize = WEBGL_TYPE_SIZES[accessorDef.type]; const TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; const elementBytes = TypedArray.BYTES_PER_ELEMENT; const itemBytes = elementBytes * itemSize; const byteOffset = accessorDef.byteOffset || 0; const byteStride = accessorDef.bufferView !== void 0 ? json.bufferViews[accessorDef.bufferView].byteStride : void 0; const normalized = accessorDef.normalized === true; let array, bufferAttribute; if (byteStride && byteStride !== itemBytes) { const ibSlice = Math.floor(byteOffset / byteStride); const ibCacheKey = "InterleavedBuffer:" + accessorDef.bufferView + ":" + accessorDef.componentType + ":" + ibSlice + ":" + accessorDef.count; let ib = parser.cache.get(ibCacheKey); if (!ib) { array = new TypedArray(bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes); ib = new InterleavedBuffer(array, byteStride / elementBytes); parser.cache.add(ibCacheKey, ib); } bufferAttribute = new InterleavedBufferAttribute(ib, itemSize, byteOffset % byteStride / elementBytes, normalized); } else { if (bufferView === null) array = new TypedArray(accessorDef.count * itemSize); else array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize); bufferAttribute = new BufferAttribute(array, itemSize, normalized); } if (accessorDef.sparse !== void 0) { const itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR; const TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType]; const byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0; const byteOffsetValues = accessorDef.sparse.values.byteOffset || 0; const sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices); const sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize); if (bufferView !== null) bufferAttribute = new BufferAttribute(bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized); for (let i = 0, il = sparseIndices.length; i < il; i++) { const index = sparseIndices[i]; bufferAttribute.setX(index, sparseValues[i * itemSize]); if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1]); if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]); if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3]); if (itemSize >= 5) throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute."); } } return bufferAttribute; }); } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures * @param {number} textureIndex * @return {Promise} */ loadTexture(textureIndex) { const json = this.json; const options = this.options; const sourceIndex = json.textures[textureIndex].source; const sourceDef = json.images[sourceIndex]; let loader = this.textureLoader; if (sourceDef.uri) { const handler = options.manager.getHandler(sourceDef.uri); if (handler !== null) loader = handler; } return this.loadTextureImage(textureIndex, sourceIndex, loader); } loadTextureImage(textureIndex, sourceIndex, loader) { const parser = this; const json = this.json; const textureDef = json.textures[textureIndex]; const sourceDef = json.images[sourceIndex]; const cacheKey = (sourceDef.uri || sourceDef.bufferView) + ":" + textureDef.sampler; if (this.textureCache[cacheKey]) return this.textureCache[cacheKey]; const promise = this.loadImageSource(sourceIndex, loader).then(function(texture) { texture.flipY = false; texture.name = textureDef.name || sourceDef.name || ""; if (texture.name === "" && typeof sourceDef.uri === "string" && sourceDef.uri.startsWith("data:image/") === false) texture.name = sourceDef.uri; const sampler = (json.samplers || {})[textureDef.sampler] || {}; texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || 1006; texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || 1008; texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || 1e3; texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || 1e3; parser.associations.set(texture, { textures: textureIndex }); return texture; }).catch(function() { return null; }); this.textureCache[cacheKey] = promise; return promise; } loadImageSource(sourceIndex, loader) { const parser = this; const json = this.json; const options = this.options; if (this.sourceCache[sourceIndex] !== void 0) return this.sourceCache[sourceIndex].then((texture) => texture.clone()); const sourceDef = json.images[sourceIndex]; const URL = self.URL || self.webkitURL; let sourceURI = sourceDef.uri || ""; let isObjectURL = false; if (sourceDef.bufferView !== void 0) sourceURI = parser.getDependency("bufferView", sourceDef.bufferView).then(function(bufferView) { isObjectURL = true; const blob = new Blob([bufferView], { type: sourceDef.mimeType }); sourceURI = URL.createObjectURL(blob); return sourceURI; }); else if (sourceDef.uri === void 0) throw new Error("THREE.GLTFLoader: Image " + sourceIndex + " is missing URI and bufferView"); const promise = Promise.resolve(sourceURI).then(function(sourceURI2) { return new Promise(function(resolve, reject) { let onLoad = resolve; if (loader.isImageBitmapLoader === true) onLoad = function(imageBitmap) { const texture = new Texture$1(imageBitmap); texture.needsUpdate = true; resolve(texture); }; loader.load(LoaderUtils.resolveURL(sourceURI2, options.path), onLoad, void 0, reject); }); }).then(function(texture) { if (isObjectURL === true) URL.revokeObjectURL(sourceURI); assignExtrasToUserData(texture, sourceDef); texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType(sourceDef.uri); return texture; }).catch(function(error) { console.error("THREE.GLTFLoader: Couldn't load texture", sourceURI); throw error; }); this.sourceCache[sourceIndex] = promise; return promise; } /** * Asynchronously assigns a texture to the given material parameters. * @param {Object} materialParams * @param {string} mapName * @param {Object} mapDef * @return {Promise} */ assignTexture(materialParams, mapName, mapDef, colorSpace) { const parser = this; return this.getDependency("texture", mapDef.index).then(function(texture) { if (!texture) return null; if (mapDef.texCoord !== void 0 && mapDef.texCoord > 0) { texture = texture.clone(); texture.channel = mapDef.texCoord; } if (parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]) { const transform = mapDef.extensions !== void 0 ? mapDef.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] : void 0; if (transform) { const gltfReference = parser.associations.get(texture); texture = parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM].extendTexture(texture, transform); parser.associations.set(texture, gltfReference); } } if (colorSpace !== void 0) { if (typeof colorSpace === "number") colorSpace = colorSpace === sRGBEncoding$1 ? SRGBColorSpace$1 : LinearSRGBColorSpace$1; if ("colorSpace" in texture) texture.colorSpace = colorSpace; else texture.encoding = colorSpace === SRGBColorSpace$1 ? sRGBEncoding$1 : LinearEncoding$1; } materialParams[mapName] = texture; return texture; }); } /** * Assigns final material to a Mesh, Line, or Points instance. The instance * already has a material (generated from the glTF material options alone) * but reuse of the same glTF material may require multiple threejs materials * to accommodate different primitive types, defines, etc. New materials will * be created if necessary, and reused from a cache. * @param {Object3D} mesh Mesh, Line, or Points instance. */ assignFinalMaterial(mesh) { const geometry = mesh.geometry; let material = mesh.material; const useDerivativeTangents = geometry.attributes.tangent === void 0; const useVertexColors = geometry.attributes.color !== void 0; const useFlatShading = geometry.attributes.normal === void 0; if (mesh.isPoints) { const cacheKey = "PointsMaterial:" + material.uuid; let pointsMaterial = this.cache.get(cacheKey); if (!pointsMaterial) { pointsMaterial = new PointsMaterial(); Material.prototype.copy.call(pointsMaterial, material); pointsMaterial.color.copy(material.color); pointsMaterial.map = material.map; pointsMaterial.sizeAttenuation = false; this.cache.add(cacheKey, pointsMaterial); } material = pointsMaterial; } else if (mesh.isLine) { const cacheKey = "LineBasicMaterial:" + material.uuid; let lineMaterial = this.cache.get(cacheKey); if (!lineMaterial) { lineMaterial = new LineBasicMaterial(); Material.prototype.copy.call(lineMaterial, material); lineMaterial.color.copy(material.color); lineMaterial.map = material.map; this.cache.add(cacheKey, lineMaterial); } material = lineMaterial; } if (useDerivativeTangents || useVertexColors || useFlatShading) { let cacheKey = "ClonedMaterial:" + material.uuid + ":"; if (useDerivativeTangents) cacheKey += "derivative-tangents:"; if (useVertexColors) cacheKey += "vertex-colors:"; if (useFlatShading) cacheKey += "flat-shading:"; let cachedMaterial = this.cache.get(cacheKey); if (!cachedMaterial) { cachedMaterial = material.clone(); if (useVertexColors) cachedMaterial.vertexColors = true; if (useFlatShading) cachedMaterial.flatShading = true; if (useDerivativeTangents) { if (cachedMaterial.normalScale) cachedMaterial.normalScale.y *= -1; if (cachedMaterial.clearcoatNormalScale) cachedMaterial.clearcoatNormalScale.y *= -1; } this.cache.add(cacheKey, cachedMaterial); this.associations.set(cachedMaterial, this.associations.get(material)); } material = cachedMaterial; } mesh.material = material; } getMaterialType() { return MeshStandardMaterial; } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials * @param {number} materialIndex * @return {Promise} */ loadMaterial(materialIndex) { const parser = this; const json = this.json; const extensions = this.extensions; const materialDef = json.materials[materialIndex]; let materialType; const materialParams = {}; const materialExtensions = materialDef.extensions || {}; const pending = []; if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) { const kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT]; materialType = kmuExtension.getMaterialType(); pending.push(kmuExtension.extendParams(materialParams, materialDef, parser)); } else { const metallicRoughness = materialDef.pbrMetallicRoughness || {}; materialParams.color = new Color(1, 1, 1); materialParams.opacity = 1; if (Array.isArray(metallicRoughness.baseColorFactor)) { const array = metallicRoughness.baseColorFactor; materialParams.color.setRGB(array[0], array[1], array[2], LinearSRGBColorSpace$1); materialParams.opacity = array[3]; } if (metallicRoughness.baseColorTexture !== void 0) pending.push(parser.assignTexture(materialParams, "map", metallicRoughness.baseColorTexture, SRGBColorSpace$1)); materialParams.metalness = metallicRoughness.metallicFactor !== void 0 ? metallicRoughness.metallicFactor : 1; materialParams.roughness = metallicRoughness.roughnessFactor !== void 0 ? metallicRoughness.roughnessFactor : 1; if (metallicRoughness.metallicRoughnessTexture !== void 0) { pending.push(parser.assignTexture(materialParams, "metalnessMap", metallicRoughness.metallicRoughnessTexture)); pending.push(parser.assignTexture(materialParams, "roughnessMap", metallicRoughness.metallicRoughnessTexture)); } materialType = this._invokeOne(function(ext) { return ext.getMaterialType && ext.getMaterialType(materialIndex); }); pending.push(Promise.all(this._invokeAll(function(ext) { return ext.extendMaterialParams && ext.extendMaterialParams(materialIndex, materialParams); }))); } if (materialDef.doubleSided === true) materialParams.side = 2; const alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE; if (alphaMode === ALPHA_MODES.BLEND) { materialParams.transparent = true; materialParams.depthWrite = false; } else { materialParams.transparent = false; if (alphaMode === ALPHA_MODES.MASK) materialParams.alphaTest = materialDef.alphaCutoff !== void 0 ? materialDef.alphaCutoff : .5; } if (materialDef.normalTexture !== void 0 && materialType !== MeshBasicMaterial) { pending.push(parser.assignTexture(materialParams, "normalMap", materialDef.normalTexture)); materialParams.normalScale = new Vector2(1, 1); if (materialDef.normalTexture.scale !== void 0) { const scale = materialDef.normalTexture.scale; materialParams.normalScale.set(scale, scale); } } if (materialDef.occlusionTexture !== void 0 && materialType !== MeshBasicMaterial) { pending.push(parser.assignTexture(materialParams, "aoMap", materialDef.occlusionTexture)); if (materialDef.occlusionTexture.strength !== void 0) materialParams.aoMapIntensity = materialDef.occlusionTexture.strength; } if (materialDef.emissiveFactor !== void 0 && materialType !== MeshBasicMaterial) { const emissiveFactor = materialDef.emissiveFactor; materialParams.emissive = new Color().setRGB(emissiveFactor[0], emissiveFactor[1], emissiveFactor[2], LinearSRGBColorSpace$1); } if (materialDef.emissiveTexture !== void 0 && materialType !== MeshBasicMaterial) pending.push(parser.assignTexture(materialParams, "emissiveMap", materialDef.emissiveTexture, SRGBColorSpace$1)); return Promise.all(pending).then(function() { const material = new materialType(materialParams); if (materialDef.name) material.name = materialDef.name; assignExtrasToUserData(material, materialDef); parser.associations.set(material, { materials: materialIndex }); if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef); return material; }); } /** When Object3D instances are targeted by animation, they need unique names. */ createUniqueName(originalName) { const sanitizedName = PropertyBinding.sanitizeNodeName(originalName || ""); if (sanitizedName in this.nodeNamesUsed) return sanitizedName + "_" + ++this.nodeNamesUsed[sanitizedName]; else { this.nodeNamesUsed[sanitizedName] = 0; return sanitizedName; } } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry * * Creates BufferGeometries from primitives. * * @param {Array} primitives * @return {Promise>} */ loadGeometries(primitives) { const parser = this; const extensions = this.extensions; const cache = this.primitiveCache; function createDracoPrimitive(primitive) { return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(primitive, parser).then(function(geometry) { return addPrimitiveAttributes(geometry, primitive, parser); }); } const pending = []; for (let i = 0, il = primitives.length; i < il; i++) { const primitive = primitives[i]; const cacheKey = createPrimitiveKey(primitive); const cached = cache[cacheKey]; if (cached) pending.push(cached.promise); else { let geometryPromise; if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) geometryPromise = createDracoPrimitive(primitive); else geometryPromise = addPrimitiveAttributes(new BufferGeometry(), primitive, parser); cache[cacheKey] = { primitive, promise: geometryPromise }; pending.push(geometryPromise); } } return Promise.all(pending); } /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes * @param {number} meshIndex * @return {Promise} */ loadMesh(meshIndex) { const parser = this; const json = this.json; const extensions = this.extensions; const meshDef = json.meshes[meshIndex]; const primitives = meshDef.primitives; const pending = []; for (let i = 0, il = primitives.length; i < il; i++) { const material = primitives[i].material === void 0 ? createDefaultMaterial(this.cache) : this.getDependency("material", primitives[i].material); pending.push(material); } pending.push(parser.loadGeometries(primitives)); return Promise.all(pending).then(function(results) { const materials = results.slice(0, results.length - 1); const geometries = results[results.length - 1]; const meshes = []; for (let i = 0, il = geometries.length; i < il; i++) { const geometry = geometries[i]; const primitive = primitives[i]; let mesh; const material = materials[i]; if (primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP || primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN || primitive.mode === void 0) { mesh = meshDef.isSkinnedMesh === true ? new SkinnedMesh(geometry, material) : new Mesh(geometry, material); if (mesh.isSkinnedMesh === true) mesh.normalizeSkinWeights(); if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) mesh.geometry = toTrianglesDrawMode(mesh.geometry, 1); else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) mesh.geometry = toTrianglesDrawMode(mesh.geometry, 2); } else if (primitive.mode === WEBGL_CONSTANTS.LINES) mesh = new LineSegments(geometry, material); else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) mesh = new Line$1(geometry, material); else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) mesh = new LineLoop(geometry, material); else if (primitive.mode === WEBGL_CONSTANTS.POINTS) mesh = new Points$1(geometry, material); else throw new Error("THREE.GLTFLoader: Primitive mode unsupported: " + primitive.mode); if (Object.keys(mesh.geometry.morphAttributes).length > 0) updateMorphTargets(mesh, meshDef); mesh.name = parser.createUniqueName(meshDef.name || "mesh_" + meshIndex); assignExtrasToUserData(mesh, meshDef); if (primitive.extensions) addUnknownExtensionsToUserData(extensions, mesh, primitive); parser.assignFinalMaterial(mesh); meshes.push(mesh); } for (let i = 0, il = meshes.length; i < il; i++) parser.associations.set(meshes[i], { meshes: meshIndex, primitives: i }); if (meshes.length === 1) { if (meshDef.extensions) addUnknownExtensionsToUserData(extensions, meshes[0], meshDef); return meshes[0]; } const group = new Group(); if (meshDef.extensions) addUnknownExtensionsToUserData(extensions, group, meshDef); parser.associations.set(group, { meshes: meshIndex }); for (let i = 0, il = meshes.length; i < il; i++) group.add(meshes[i]); return group; }); } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras * @param {number} cameraIndex * @return {Promise} */ loadCamera(cameraIndex) { let camera; const cameraDef = this.json.cameras[cameraIndex]; const params = cameraDef[cameraDef.type]; if (!params) { console.warn("THREE.GLTFLoader: Missing camera parameters."); return; } if (cameraDef.type === "perspective") camera = new PerspectiveCamera$1(MathUtils.radToDeg(params.yfov), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6); else if (cameraDef.type === "orthographic") camera = new OrthographicCamera$1(-params.xmag, params.xmag, params.ymag, -params.ymag, params.znear, params.zfar); if (cameraDef.name) camera.name = this.createUniqueName(cameraDef.name); assignExtrasToUserData(camera, cameraDef); return Promise.resolve(camera); } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins * @param {number} skinIndex * @return {Promise} */ loadSkin(skinIndex) { const skinDef = this.json.skins[skinIndex]; const pending = []; for (let i = 0, il = skinDef.joints.length; i < il; i++) pending.push(this._loadNodeShallow(skinDef.joints[i])); if (skinDef.inverseBindMatrices !== void 0) pending.push(this.getDependency("accessor", skinDef.inverseBindMatrices)); else pending.push(null); return Promise.all(pending).then(function(results) { const inverseBindMatrices = results.pop(); const jointNodes = results; const bones = []; const boneInverses = []; for (let i = 0, il = jointNodes.length; i < il; i++) { const jointNode = jointNodes[i]; if (jointNode) { bones.push(jointNode); const mat = new Matrix4(); if (inverseBindMatrices !== null) mat.fromArray(inverseBindMatrices.array, i * 16); boneInverses.push(mat); } else console.warn("THREE.GLTFLoader: Joint \"%s\" could not be found.", skinDef.joints[i]); } return new Skeleton(bones, boneInverses); }); } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations * @param {number} animationIndex * @return {Promise} */ loadAnimation(animationIndex) { const json = this.json; const parser = this; const animationDef = json.animations[animationIndex]; const animationName = animationDef.name ? animationDef.name : "animation_" + animationIndex; const pendingNodes = []; const pendingInputAccessors = []; const pendingOutputAccessors = []; const pendingSamplers = []; const pendingTargets = []; for (let i = 0, il = animationDef.channels.length; i < il; i++) { const channel = animationDef.channels[i]; const sampler = animationDef.samplers[channel.sampler]; const target = channel.target; const name = target.node; const input = animationDef.parameters !== void 0 ? animationDef.parameters[sampler.input] : sampler.input; const output = animationDef.parameters !== void 0 ? animationDef.parameters[sampler.output] : sampler.output; if (target.node === void 0) continue; pendingNodes.push(this.getDependency("node", name)); pendingInputAccessors.push(this.getDependency("accessor", input)); pendingOutputAccessors.push(this.getDependency("accessor", output)); pendingSamplers.push(sampler); pendingTargets.push(target); } return Promise.all([ Promise.all(pendingNodes), Promise.all(pendingInputAccessors), Promise.all(pendingOutputAccessors), Promise.all(pendingSamplers), Promise.all(pendingTargets) ]).then(function(dependencies) { const nodes = dependencies[0]; const inputAccessors = dependencies[1]; const outputAccessors = dependencies[2]; const samplers = dependencies[3]; const targets = dependencies[4]; const tracks = []; for (let i = 0, il = nodes.length; i < il; i++) { const node = nodes[i]; const inputAccessor = inputAccessors[i]; const outputAccessor = outputAccessors[i]; const sampler = samplers[i]; const target = targets[i]; if (node === void 0) continue; if (node.updateMatrix) node.updateMatrix(); const createdTracks = parser._createAnimationTracks(node, inputAccessor, outputAccessor, sampler, target); if (createdTracks) for (let k = 0; k < createdTracks.length; k++) tracks.push(createdTracks[k]); } return new AnimationClip(animationName, void 0, tracks); }); } createNodeMesh(nodeIndex) { const json = this.json; const parser = this; const nodeDef = json.nodes[nodeIndex]; if (nodeDef.mesh === void 0) return null; return parser.getDependency("mesh", nodeDef.mesh).then(function(mesh) { const node = parser._getNodeRef(parser.meshCache, nodeDef.mesh, mesh); if (nodeDef.weights !== void 0) node.traverse(function(o) { if (!o.isMesh) return; for (let i = 0, il = nodeDef.weights.length; i < il; i++) o.morphTargetInfluences[i] = nodeDef.weights[i]; }); return node; }); } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy * @param {number} nodeIndex * @return {Promise} */ loadNode(nodeIndex) { const json = this.json; const parser = this; const nodeDef = json.nodes[nodeIndex]; const nodePending = parser._loadNodeShallow(nodeIndex); const childPending = []; const childrenDef = nodeDef.children || []; for (let i = 0, il = childrenDef.length; i < il; i++) childPending.push(parser.getDependency("node", childrenDef[i])); const skeletonPending = nodeDef.skin === void 0 ? Promise.resolve(null) : parser.getDependency("skin", nodeDef.skin); return Promise.all([ nodePending, Promise.all(childPending), skeletonPending ]).then(function(results) { const node = results[0]; const children = results[1]; const skeleton = results[2]; if (skeleton !== null) node.traverse(function(mesh) { if (!mesh.isSkinnedMesh) return; mesh.bind(skeleton, _identityMatrix); }); for (let i = 0, il = children.length; i < il; i++) node.add(children[i]); return node; }); } _loadNodeShallow(nodeIndex) { const json = this.json; const extensions = this.extensions; const parser = this; if (this.nodeCache[nodeIndex] !== void 0) return this.nodeCache[nodeIndex]; const nodeDef = json.nodes[nodeIndex]; const nodeName = nodeDef.name ? parser.createUniqueName(nodeDef.name) : ""; const pending = []; const meshPromise = parser._invokeOne(function(ext) { return ext.createNodeMesh && ext.createNodeMesh(nodeIndex); }); if (meshPromise) pending.push(meshPromise); if (nodeDef.camera !== void 0) pending.push(parser.getDependency("camera", nodeDef.camera).then(function(camera) { return parser._getNodeRef(parser.cameraCache, nodeDef.camera, camera); })); parser._invokeAll(function(ext) { return ext.createNodeAttachment && ext.createNodeAttachment(nodeIndex); }).forEach(function(promise) { pending.push(promise); }); this.nodeCache[nodeIndex] = Promise.all(pending).then(function(objects) { let node; if (nodeDef.isBone === true) node = new Bone(); else if (objects.length > 1) node = new Group(); else if (objects.length === 1) node = objects[0]; else node = new Object3D(); if (node !== objects[0]) for (let i = 0, il = objects.length; i < il; i++) node.add(objects[i]); if (nodeDef.name) { node.userData.name = nodeDef.name; node.name = nodeName; } assignExtrasToUserData(node, nodeDef); if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef); if (nodeDef.matrix !== void 0) { const matrix = new Matrix4(); matrix.fromArray(nodeDef.matrix); node.applyMatrix4(matrix); } else { if (nodeDef.translation !== void 0) node.position.fromArray(nodeDef.translation); if (nodeDef.rotation !== void 0) node.quaternion.fromArray(nodeDef.rotation); if (nodeDef.scale !== void 0) node.scale.fromArray(nodeDef.scale); } if (!parser.associations.has(node)) parser.associations.set(node, {}); parser.associations.get(node).nodes = nodeIndex; return node; }); return this.nodeCache[nodeIndex]; } /** * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes * @param {number} sceneIndex * @return {Promise} */ loadScene(sceneIndex) { const extensions = this.extensions; const sceneDef = this.json.scenes[sceneIndex]; const parser = this; const scene = new Group(); if (sceneDef.name) scene.name = parser.createUniqueName(sceneDef.name); assignExtrasToUserData(scene, sceneDef); if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef); const nodeIds = sceneDef.nodes || []; const pending = []; for (let i = 0, il = nodeIds.length; i < il; i++) pending.push(parser.getDependency("node", nodeIds[i])); return Promise.all(pending).then(function(nodes) { for (let i = 0, il = nodes.length; i < il; i++) scene.add(nodes[i]); const reduceAssociations = (node) => { const reducedAssociations = /* @__PURE__ */ new Map(); for (const [key, value] of parser.associations) if (key instanceof Material || key instanceof Texture$1) reducedAssociations.set(key, value); node.traverse((node2) => { const mappings = parser.associations.get(node2); if (mappings != null) reducedAssociations.set(node2, mappings); }); return reducedAssociations; }; parser.associations = reduceAssociations(scene); return scene; }); } _createAnimationTracks(node, inputAccessor, outputAccessor, sampler, target) { const tracks = []; const targetName = node.name ? node.name : node.uuid; const targetNames = []; if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) node.traverse(function(object) { if (object.morphTargetInfluences) targetNames.push(object.name ? object.name : object.uuid); }); else targetNames.push(targetName); let TypedKeyframeTrack; switch (PATH_PROPERTIES[target.path]) { case PATH_PROPERTIES.weights: TypedKeyframeTrack = NumberKeyframeTrack; break; case PATH_PROPERTIES.rotation: TypedKeyframeTrack = QuaternionKeyframeTrack; break; case PATH_PROPERTIES.position: case PATH_PROPERTIES.scale: TypedKeyframeTrack = VectorKeyframeTrack; break; default: switch (outputAccessor.itemSize) { case 1: TypedKeyframeTrack = NumberKeyframeTrack; break; default: TypedKeyframeTrack = VectorKeyframeTrack; break; } break; } const interpolation = sampler.interpolation !== void 0 ? INTERPOLATION[sampler.interpolation] : InterpolateLinear; const outputArray = this._getArrayFromAccessor(outputAccessor); for (let j = 0, jl = targetNames.length; j < jl; j++) { const track = new TypedKeyframeTrack(targetNames[j] + "." + PATH_PROPERTIES[target.path], inputAccessor.array, outputArray, interpolation); if (sampler.interpolation === "CUBICSPLINE") this._createCubicSplineTrackInterpolant(track); tracks.push(track); } return tracks; } _getArrayFromAccessor(accessor) { let outputArray = accessor.array; if (accessor.normalized) { const scale = getNormalizedComponentScale(outputArray.constructor); const scaled = new Float32Array(outputArray.length); for (let j = 0, jl = outputArray.length; j < jl; j++) scaled[j] = outputArray[j] * scale; outputArray = scaled; } return outputArray; } _createCubicSplineTrackInterpolant(track) { track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) { return new (this instanceof QuaternionKeyframeTrack ? GLTFCubicSplineQuaternionInterpolant : GLTFCubicSplineInterpolant)(this.times, this.values, this.getValueSize() / 3, result); }; track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true; } }; function computeBounds(geometry, primitiveDef, parser) { const attributes = primitiveDef.attributes; const box = new Box3(); if (attributes.POSITION !== void 0) { const accessor = parser.json.accessors[attributes.POSITION]; const min = accessor.min; const max = accessor.max; if (min !== void 0 && max !== void 0) { box.set(new Vector3(min[0], min[1], min[2]), new Vector3(max[0], max[1], max[2])); if (accessor.normalized) { const boxScale = getNormalizedComponentScale(WEBGL_COMPONENT_TYPES[accessor.componentType]); box.min.multiplyScalar(boxScale); box.max.multiplyScalar(boxScale); } } else { console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION."); return; } } else return; const targets = primitiveDef.targets; if (targets !== void 0) { const maxDisplacement = new Vector3(); const vector = new Vector3(); for (let i = 0, il = targets.length; i < il; i++) { const target = targets[i]; if (target.POSITION !== void 0) { const accessor = parser.json.accessors[target.POSITION]; const min = accessor.min; const max = accessor.max; if (min !== void 0 && max !== void 0) { vector.setX(Math.max(Math.abs(min[0]), Math.abs(max[0]))); vector.setY(Math.max(Math.abs(min[1]), Math.abs(max[1]))); vector.setZ(Math.max(Math.abs(min[2]), Math.abs(max[2]))); if (accessor.normalized) { const boxScale = getNormalizedComponentScale(WEBGL_COMPONENT_TYPES[accessor.componentType]); vector.multiplyScalar(boxScale); } maxDisplacement.max(vector); } else console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION."); } } box.expandByVector(maxDisplacement); } geometry.boundingBox = box; const sphere = new Sphere$1(); box.getCenter(sphere.center); sphere.radius = box.min.distanceTo(box.max) / 2; geometry.boundingSphere = sphere; } function addPrimitiveAttributes(geometry, primitiveDef, parser) { const attributes = primitiveDef.attributes; const pending = []; function assignAttributeAccessor(accessorIndex, attributeName) { return parser.getDependency("accessor", accessorIndex).then(function(accessor) { geometry.setAttribute(attributeName, accessor); }); } for (const gltfAttributeName in attributes) { const threeAttributeName = ATTRIBUTES[gltfAttributeName] || gltfAttributeName.toLowerCase(); if (threeAttributeName in geometry.attributes) continue; pending.push(assignAttributeAccessor(attributes[gltfAttributeName], threeAttributeName)); } if (primitiveDef.indices !== void 0 && !geometry.index) { const accessor = parser.getDependency("accessor", primitiveDef.indices).then(function(accessor2) { geometry.setIndex(accessor2); }); pending.push(accessor); } assignExtrasToUserData(geometry, primitiveDef); computeBounds(geometry, primitiveDef, parser); return Promise.all(pending).then(function() { return primitiveDef.targets !== void 0 ? addMorphTargets(geometry, primitiveDef.targets, parser) : geometry; }); } //#endregion //#region node_modules/three-stdlib/geometries/DecalGeometry.js var DecalGeometry = class extends BufferGeometry { constructor(mesh, position, orientation, size) { super(); const vertices = []; const normals = []; const uvs = []; const plane = new Vector3(); const projectorMatrix = new Matrix4(); projectorMatrix.makeRotationFromEuler(orientation); projectorMatrix.setPosition(position); const projectorMatrixInverse = new Matrix4(); projectorMatrixInverse.copy(projectorMatrix).invert(); generate(); this.setAttribute("position", new Float32BufferAttribute(vertices, 3)); this.setAttribute("normal", new Float32BufferAttribute(normals, 3)); this.setAttribute("uv", new Float32BufferAttribute(uvs, 2)); function generate() { let i; let decalVertices = []; const vertex = new Vector3(); const normal = new Vector3(); if (mesh.geometry.isGeometry === true) { console.error("THREE.DecalGeometry no longer supports THREE.Geometry. Use BufferGeometry instead."); return; } const geometry = mesh.geometry; const positionAttribute = geometry.attributes.position; const normalAttribute = geometry.attributes.normal; if (geometry.index !== null) { const index = geometry.index; for (i = 0; i < index.count; i++) { vertex.fromBufferAttribute(positionAttribute, index.getX(i)); normal.fromBufferAttribute(normalAttribute, index.getX(i)); pushDecalVertex(decalVertices, vertex, normal); } } else for (i = 0; i < positionAttribute.count; i++) { vertex.fromBufferAttribute(positionAttribute, i); normal.fromBufferAttribute(normalAttribute, i); pushDecalVertex(decalVertices, vertex, normal); } decalVertices = clipGeometry(decalVertices, plane.set(1, 0, 0)); decalVertices = clipGeometry(decalVertices, plane.set(-1, 0, 0)); decalVertices = clipGeometry(decalVertices, plane.set(0, 1, 0)); decalVertices = clipGeometry(decalVertices, plane.set(0, -1, 0)); decalVertices = clipGeometry(decalVertices, plane.set(0, 0, 1)); decalVertices = clipGeometry(decalVertices, plane.set(0, 0, -1)); for (i = 0; i < decalVertices.length; i++) { const decalVertex = decalVertices[i]; uvs.push(.5 + decalVertex.position.x / size.x, .5 + decalVertex.position.y / size.y); decalVertex.position.applyMatrix4(projectorMatrix); vertices.push(decalVertex.position.x, decalVertex.position.y, decalVertex.position.z); normals.push(decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z); } } function pushDecalVertex(decalVertices, vertex, normal) { vertex.applyMatrix4(mesh.matrixWorld); vertex.applyMatrix4(projectorMatrixInverse); normal.transformDirection(mesh.matrixWorld); decalVertices.push(new DecalVertex(vertex.clone(), normal.clone())); } function clipGeometry(inVertices, plane2) { const outVertices = []; const s = .5 * Math.abs(size.dot(plane2)); for (let i = 0; i < inVertices.length; i += 3) { let v1Out, v2Out, v3Out, total = 0; let nV1, nV2, nV3, nV4; const d1 = inVertices[i + 0].position.dot(plane2) - s; const d2 = inVertices[i + 1].position.dot(plane2) - s; const d3 = inVertices[i + 2].position.dot(plane2) - s; v1Out = d1 > 0; v2Out = d2 > 0; v3Out = d3 > 0; total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0); switch (total) { case 0: outVertices.push(inVertices[i]); outVertices.push(inVertices[i + 1]); outVertices.push(inVertices[i + 2]); break; case 1: if (v1Out) { nV1 = inVertices[i + 1]; nV2 = inVertices[i + 2]; nV3 = clip(inVertices[i], nV1, plane2, s); nV4 = clip(inVertices[i], nV2, plane2, s); } if (v2Out) { nV1 = inVertices[i]; nV2 = inVertices[i + 2]; nV3 = clip(inVertices[i + 1], nV1, plane2, s); nV4 = clip(inVertices[i + 1], nV2, plane2, s); outVertices.push(nV3); outVertices.push(nV2.clone()); outVertices.push(nV1.clone()); outVertices.push(nV2.clone()); outVertices.push(nV3.clone()); outVertices.push(nV4); break; } if (v3Out) { nV1 = inVertices[i]; nV2 = inVertices[i + 1]; nV3 = clip(inVertices[i + 2], nV1, plane2, s); nV4 = clip(inVertices[i + 2], nV2, plane2, s); } outVertices.push(nV1.clone()); outVertices.push(nV2.clone()); outVertices.push(nV3); outVertices.push(nV4); outVertices.push(nV3.clone()); outVertices.push(nV2.clone()); break; case 2: if (!v1Out) { nV1 = inVertices[i].clone(); nV2 = clip(nV1, inVertices[i + 1], plane2, s); nV3 = clip(nV1, inVertices[i + 2], plane2, s); outVertices.push(nV1); outVertices.push(nV2); outVertices.push(nV3); } if (!v2Out) { nV1 = inVertices[i + 1].clone(); nV2 = clip(nV1, inVertices[i + 2], plane2, s); nV3 = clip(nV1, inVertices[i], plane2, s); outVertices.push(nV1); outVertices.push(nV2); outVertices.push(nV3); } if (!v3Out) { nV1 = inVertices[i + 2].clone(); nV2 = clip(nV1, inVertices[i], plane2, s); nV3 = clip(nV1, inVertices[i + 1], plane2, s); outVertices.push(nV1); outVertices.push(nV2); outVertices.push(nV3); } break; } } return outVertices; } function clip(v0, v1, p, s) { const d0 = v0.position.dot(p) - s; const s0 = d0 / (d0 - (v1.position.dot(p) - s)); return new DecalVertex(new Vector3(v0.position.x + s0 * (v1.position.x - v0.position.x), v0.position.y + s0 * (v1.position.y - v0.position.y), v0.position.z + s0 * (v1.position.z - v0.position.z)), new Vector3(v0.normal.x + s0 * (v1.normal.x - v0.normal.x), v0.normal.y + s0 * (v1.normal.y - v0.normal.y), v0.normal.z + s0 * (v1.normal.z - v0.normal.z))); } } }; var DecalVertex = class { constructor(position, normal) { this.position = position; this.normal = normal; } clone() { return new this.constructor(this.position.clone(), this.normal.clone()); } }; //#endregion //#region node_modules/three-stdlib/geometries/TextGeometry.js var TextGeometry = class extends ExtrudeGeometry { constructor(text, parameters = {}) { const { bevelEnabled = false, bevelSize = 8, bevelThickness = 10, font, height = 50, size = 100, lineHeight = 1, letterSpacing = 0, ...rest } = parameters; if (font === void 0) super(); else { const shapes = font.generateShapes(text, size, { lineHeight, letterSpacing }); super(shapes, { ...rest, bevelEnabled, bevelSize, bevelThickness, depth: height }); } this.type = "TextGeometry"; } }; //#endregion //#region node_modules/three-stdlib/shaders/GammaCorrectionShader.js var GammaCorrectionShader = { uniforms: { tDiffuse: { value: null } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: ` uniform sampler2D tDiffuse; varying vec2 vUv; void main() { vec4 tex = texture2D( tDiffuse, vUv ); #ifdef LinearTosRGB gl_FragColor = LinearTosRGB( tex ); #else gl_FragColor = sRGBTransferOETF( tex ); #endif } ` }; //#endregion //#region node_modules/three-stdlib/shaders/HorizontalBlurShader.js var HorizontalBlurShader = { uniforms: { tDiffuse: { value: null }, h: { value: 1 / 512 } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: ` uniform sampler2D tDiffuse; uniform float h; varying vec2 vUv; void main() { vec4 sum = vec4( 0.0 ); sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051; sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918; sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245; sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633; sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * h, vUv.y ) ) * 0.1531; sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * h, vUv.y ) ) * 0.12245; sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * h, vUv.y ) ) * 0.0918; sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * h, vUv.y ) ) * 0.051; gl_FragColor = sum; } ` }; //#endregion //#region node_modules/three-stdlib/shaders/VerticalBlurShader.js var VerticalBlurShader = { uniforms: { tDiffuse: { value: null }, v: { value: 1 / 512 } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: ` uniform sampler2D tDiffuse; uniform float v; varying vec2 vUv; void main() { vec4 sum = vec4( 0.0 ); sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * v ) ) * 0.051; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * v ) ) * 0.0918; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * v ) ) * 0.12245; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * v ) ) * 0.1531; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * v ) ) * 0.1531; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * v ) ) * 0.12245; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * v ) ) * 0.0918; sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * v ) ) * 0.051; gl_FragColor = sum; } ` }; //#endregion //#region node_modules/three-stdlib/interactive/SelectionBox.js var frustum = /* @__PURE__ */ new Frustum(); var center$1 = /* @__PURE__ */ new Vector3(); var tmpPoint = /* @__PURE__ */ new Vector3(); var vecNear = /* @__PURE__ */ new Vector3(); var vecTopLeft = /* @__PURE__ */ new Vector3(); var vecTopRight = /* @__PURE__ */ new Vector3(); var vecDownRight = /* @__PURE__ */ new Vector3(); var vecDownLeft = /* @__PURE__ */ new Vector3(); var vecFarTopLeft = /* @__PURE__ */ new Vector3(); var vecFarTopRight = /* @__PURE__ */ new Vector3(); var vecFarDownRight = /* @__PURE__ */ new Vector3(); var vecFarDownLeft = /* @__PURE__ */ new Vector3(); var vectemp1 = /* @__PURE__ */ new Vector3(); var vectemp2 = /* @__PURE__ */ new Vector3(); var vectemp3 = /* @__PURE__ */ new Vector3(); var SelectionBox = class { constructor(camera, scene, deep) { this.camera = camera; this.scene = scene; this.startPoint = new Vector3(); this.endPoint = new Vector3(); this.collection = []; this.deep = deep || Number.MAX_VALUE; } select(startPoint, endPoint) { this.startPoint = startPoint || this.startPoint; this.endPoint = endPoint || this.endPoint; this.collection = []; this.updateFrustum(this.startPoint, this.endPoint); this.searchChildInFrustum(frustum, this.scene); return this.collection; } updateFrustum(startPoint, endPoint) { startPoint = startPoint || this.startPoint; endPoint = endPoint || this.endPoint; if (startPoint.x === endPoint.x) endPoint.x += Number.EPSILON; if (startPoint.y === endPoint.y) endPoint.y += Number.EPSILON; this.camera.updateProjectionMatrix(); this.camera.updateMatrixWorld(); if (this.camera.isPerspectiveCamera) { tmpPoint.copy(startPoint); tmpPoint.x = Math.min(startPoint.x, endPoint.x); tmpPoint.y = Math.max(startPoint.y, endPoint.y); endPoint.x = Math.max(startPoint.x, endPoint.x); endPoint.y = Math.min(startPoint.y, endPoint.y); vecNear.setFromMatrixPosition(this.camera.matrixWorld); vecTopLeft.copy(tmpPoint); vecTopRight.set(endPoint.x, tmpPoint.y, 0); vecDownRight.copy(endPoint); vecDownLeft.set(tmpPoint.x, endPoint.y, 0); vecTopLeft.unproject(this.camera); vecTopRight.unproject(this.camera); vecDownRight.unproject(this.camera); vecDownLeft.unproject(this.camera); vectemp1.copy(vecTopLeft).sub(vecNear); vectemp2.copy(vecTopRight).sub(vecNear); vectemp3.copy(vecDownRight).sub(vecNear); vectemp1.normalize(); vectemp2.normalize(); vectemp3.normalize(); vectemp1.multiplyScalar(this.deep); vectemp2.multiplyScalar(this.deep); vectemp3.multiplyScalar(this.deep); vectemp1.add(vecNear); vectemp2.add(vecNear); vectemp3.add(vecNear); var planes = frustum.planes; planes[0].setFromCoplanarPoints(vecNear, vecTopLeft, vecTopRight); planes[1].setFromCoplanarPoints(vecNear, vecTopRight, vecDownRight); planes[2].setFromCoplanarPoints(vecDownRight, vecDownLeft, vecNear); planes[3].setFromCoplanarPoints(vecDownLeft, vecTopLeft, vecNear); planes[4].setFromCoplanarPoints(vecTopRight, vecDownRight, vecDownLeft); planes[5].setFromCoplanarPoints(vectemp3, vectemp2, vectemp1); planes[5].normal.multiplyScalar(-1); } else if (this.camera.isOrthographicCamera) { const left = Math.min(startPoint.x, endPoint.x); const top = Math.max(startPoint.y, endPoint.y); const right = Math.max(startPoint.x, endPoint.x); const down = Math.min(startPoint.y, endPoint.y); vecTopLeft.set(left, top, -1); vecTopRight.set(right, top, -1); vecDownRight.set(right, down, -1); vecDownLeft.set(left, down, -1); vecFarTopLeft.set(left, top, 1); vecFarTopRight.set(right, top, 1); vecFarDownRight.set(right, down, 1); vecFarDownLeft.set(left, down, 1); vecTopLeft.unproject(this.camera); vecTopRight.unproject(this.camera); vecDownRight.unproject(this.camera); vecDownLeft.unproject(this.camera); vecFarTopLeft.unproject(this.camera); vecFarTopRight.unproject(this.camera); vecFarDownRight.unproject(this.camera); vecFarDownLeft.unproject(this.camera); var planes = frustum.planes; planes[0].setFromCoplanarPoints(vecTopLeft, vecFarTopLeft, vecFarTopRight); planes[1].setFromCoplanarPoints(vecTopRight, vecFarTopRight, vecFarDownRight); planes[2].setFromCoplanarPoints(vecFarDownRight, vecFarDownLeft, vecDownLeft); planes[3].setFromCoplanarPoints(vecFarDownLeft, vecFarTopLeft, vecTopLeft); planes[4].setFromCoplanarPoints(vecTopRight, vecDownRight, vecDownLeft); planes[5].setFromCoplanarPoints(vecFarDownRight, vecFarTopRight, vecFarTopLeft); planes[5].normal.multiplyScalar(-1); } else console.error("THREE.SelectionBox: Unsupported camera type."); } searchChildInFrustum(frustum2, object) { if (object.isMesh || object.isLine || object.isPoints) { if (object.material !== void 0) { if (object.geometry.boundingSphere === null) object.geometry.computeBoundingSphere(); center$1.copy(object.geometry.boundingSphere.center); center$1.applyMatrix4(object.matrixWorld); if (frustum2.containsPoint(center$1)) this.collection.push(object); } } if (object.children.length > 0) for (let x = 0; x < object.children.length; x++) this.searchChildInFrustum(frustum2, object.children[x]); } }; //#endregion //#region node_modules/three-stdlib/effects/AsciiEffect.js var AsciiEffect = class { constructor(renderer, charSet = " .:-=+*#%@", options = {}) { const fResolution = options["resolution"] || .15; const iScale = options["scale"] || 1; const bColor = options["color"] || false; const bAlpha = options["alpha"] || false; const bBlock = options["block"] || false; const bInvert = options["invert"] || false; const strResolution = options["strResolution"] || "low"; let width, height; const domElement = document.createElement("div"); domElement.style.cursor = "default"; const oAscii = document.createElement("table"); domElement.appendChild(oAscii); let iWidth, iHeight; let oImg; this.setSize = function(w, h) { width = w; height = h; renderer.setSize(w, h); initAsciiSize(); }; this.render = function(scene, camera) { renderer.render(scene, camera); asciifyImage(oAscii); }; this.domElement = domElement; function initAsciiSize() { iWidth = Math.floor(width * fResolution); iHeight = Math.floor(height * fResolution); oCanvas.width = iWidth; oCanvas.height = iHeight; oImg = renderer.domElement; if (oImg.style.backgroundColor) { oAscii.rows[0].cells[0].style.backgroundColor = oImg.style.backgroundColor; oAscii.rows[0].cells[0].style.color = oImg.style.color; } oAscii.cellSpacing = 0; oAscii.cellPadding = 0; const oStyle = oAscii.style; oStyle.whiteSpace = "pre"; oStyle.margin = "0px"; oStyle.padding = "0px"; oStyle.letterSpacing = fLetterSpacing + "px"; oStyle.fontFamily = strFont; oStyle.fontSize = fFontSize + "px"; oStyle.lineHeight = fLineHeight + "px"; oStyle.textAlign = "left"; oStyle.textDecoration = "none"; } const aDefaultCharList = " .,:;i1tfLCG08@".split(""); const aDefaultColorCharList = " CGO08@".split(""); const strFont = "courier new, monospace"; const oCanvasImg = renderer.domElement; const oCanvas = document.createElement("canvas"); if (!oCanvas.getContext) return; const oCtx = oCanvas.getContext("2d"); if (!oCtx.getImageData) return; let aCharList = bColor ? aDefaultColorCharList : aDefaultCharList; if (charSet) aCharList = charSet; const fFontSize = 2 / fResolution * iScale; const fLineHeight = 2 / fResolution * iScale; let fLetterSpacing = 0; if (strResolution == "low") switch (iScale) { case 1: fLetterSpacing = -1; break; case 2: case 3: fLetterSpacing = -2.1; break; case 4: fLetterSpacing = -3.1; break; case 5: fLetterSpacing = -4.15; break; } if (strResolution == "medium") switch (iScale) { case 1: fLetterSpacing = 0; break; case 2: fLetterSpacing = -1; break; case 3: fLetterSpacing = -1.04; break; case 4: case 5: fLetterSpacing = -2.1; break; } if (strResolution == "high") switch (iScale) { case 1: case 2: fLetterSpacing = 0; break; case 3: case 4: case 5: fLetterSpacing = -1; break; } function asciifyImage(oAscii2) { oCtx.clearRect(0, 0, iWidth, iHeight); oCtx.drawImage(oCanvasImg, 0, 0, iWidth, iHeight); const oImgData = oCtx.getImageData(0, 0, iWidth, iHeight).data; let strChars = ""; for (let y = 0; y < iHeight; y += 2) { for (let x = 0; x < iWidth; x++) { const iOffset = (y * iWidth + x) * 4; const iRed = oImgData[iOffset]; const iGreen = oImgData[iOffset + 1]; const iBlue = oImgData[iOffset + 2]; const iAlpha = oImgData[iOffset + 3]; let iCharIdx; let fBrightness; fBrightness = (.3 * iRed + .59 * iGreen + .11 * iBlue) / 255; if (iAlpha == 0) fBrightness = 1; iCharIdx = Math.floor((1 - fBrightness) * (aCharList.length - 1)); if (bInvert) iCharIdx = aCharList.length - iCharIdx - 1; let strThisChar = aCharList[iCharIdx]; if (strThisChar === void 0 || strThisChar == " ") strThisChar = " "; if (bColor) strChars += "" + strThisChar + ""; else strChars += strThisChar; } strChars += "
"; } oAscii2.innerHTML = `${strChars}`; } } }; //#endregion //#region node_modules/three-stdlib/curves/NURBSUtils.js function findSpan(p, u, U) { const n = U.length - p - 1; if (u >= U[n]) return n - 1; if (u <= U[p]) return p; let low = p; let high = n; let mid = Math.floor((low + high) / 2); while (u < U[mid] || u >= U[mid + 1]) { if (u < U[mid]) high = mid; else low = mid; mid = Math.floor((low + high) / 2); } return mid; } function calcBasisFunctions(span, u, p, U) { const N = []; const left = []; const right = []; N[0] = 1; for (let j = 1; j <= p; ++j) { left[j] = u - U[span + 1 - j]; right[j] = U[span + j] - u; let saved = 0; for (let r = 0; r < j; ++r) { const rv = right[r + 1]; const lv = left[j - r]; const temp = N[r] / (rv + lv); N[r] = saved + rv * temp; saved = lv * temp; } N[j] = saved; } return N; } function calcBSplinePoint(p, U, P, u) { const span = findSpan(p, u, U); const N = calcBasisFunctions(span, u, p, U); const C = new Vector4(0, 0, 0, 0); for (let j = 0; j <= p; ++j) { const point = P[span - p + j]; const Nj = N[j]; const wNj = point.w * Nj; C.x += point.x * wNj; C.y += point.y * wNj; C.z += point.z * wNj; C.w += point.w * Nj; } return C; } function calcBasisFunctionDerivatives(span, u, p, n, U) { const zeroArr = []; for (let i = 0; i <= p; ++i) zeroArr[i] = 0; const ders = []; for (let i = 0; i <= n; ++i) ders[i] = zeroArr.slice(0); const ndu = []; for (let i = 0; i <= p; ++i) ndu[i] = zeroArr.slice(0); ndu[0][0] = 1; const left = zeroArr.slice(0); const right = zeroArr.slice(0); for (let j = 1; j <= p; ++j) { left[j] = u - U[span + 1 - j]; right[j] = U[span + j] - u; let saved = 0; for (let r2 = 0; r2 < j; ++r2) { const rv = right[r2 + 1]; const lv = left[j - r2]; ndu[j][r2] = rv + lv; const temp = ndu[r2][j - 1] / ndu[j][r2]; ndu[r2][j] = saved + rv * temp; saved = lv * temp; } ndu[j][j] = saved; } for (let j = 0; j <= p; ++j) ders[0][j] = ndu[j][p]; for (let r2 = 0; r2 <= p; ++r2) { let s1 = 0; let s2 = 1; const a = []; for (let i = 0; i <= p; ++i) a[i] = zeroArr.slice(0); a[0][0] = 1; for (let k = 1; k <= n; ++k) { let d = 0; const rk = r2 - k; const pk = p - k; if (r2 >= k) { a[s2][0] = a[s1][0] / ndu[pk + 1][rk]; d = a[s2][0] * ndu[rk][pk]; } const j1 = rk >= -1 ? 1 : -rk; const j2 = r2 - 1 <= pk ? k - 1 : p - r2; for (let j3 = j1; j3 <= j2; ++j3) { a[s2][j3] = (a[s1][j3] - a[s1][j3 - 1]) / ndu[pk + 1][rk + j3]; d += a[s2][j3] * ndu[rk + j3][pk]; } if (r2 <= pk) { a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r2]; d += a[s2][k] * ndu[r2][pk]; } ders[k][r2] = d; const j = s1; s1 = s2; s2 = j; } } let r = p; for (let k = 1; k <= n; ++k) { for (let j = 0; j <= p; ++j) ders[k][j] *= r; r *= p - k; } return ders; } function calcBSplineDerivatives(p, U, P, u, nd) { const du = nd < p ? nd : p; const CK = []; const span = findSpan(p, u, U); const nders = calcBasisFunctionDerivatives(span, u, p, du, U); const Pw = []; for (let i = 0; i < P.length; ++i) { const point = P[i].clone(); const w = point.w; point.x *= w; point.y *= w; point.z *= w; Pw[i] = point; } for (let k = 0; k <= du; ++k) { const point = Pw[span - p].clone().multiplyScalar(nders[k][0]); for (let j = 1; j <= p; ++j) point.add(Pw[span - p + j].clone().multiplyScalar(nders[k][j])); CK[k] = point; } for (let k = du + 1; k <= nd + 1; ++k) CK[k] = new Vector4(0, 0, 0); return CK; } function calcKoverI(k, i) { let nom = 1; for (let j = 2; j <= k; ++j) nom *= j; let denom = 1; for (let j = 2; j <= i; ++j) denom *= j; for (let j = 2; j <= k - i; ++j) denom *= j; return nom / denom; } function calcRationalCurveDerivatives(Pders) { const nd = Pders.length; const Aders = []; const wders = []; for (let i = 0; i < nd; ++i) { const point = Pders[i]; Aders[i] = new Vector3(point.x, point.y, point.z); wders[i] = point.w; } const CK = []; for (let k = 0; k < nd; ++k) { const v = Aders[k].clone(); for (let i = 1; i <= k; ++i) v.sub(CK[k - i].clone().multiplyScalar(calcKoverI(k, i) * wders[i])); CK[k] = v.divideScalar(wders[0]); } return CK; } function calcNURBSDerivatives(p, U, P, u, nd) { return calcRationalCurveDerivatives(calcBSplineDerivatives(p, U, P, u, nd)); } //#endregion //#region node_modules/three-stdlib/curves/NURBSCurve.js var NURBSCurve = class extends Curve { constructor(degree, knots, controlPoints, startKnot, endKnot) { super(); this.degree = degree; this.knots = knots; this.controlPoints = []; this.startKnot = startKnot || 0; this.endKnot = endKnot || this.knots.length - 1; for (let i = 0; i < controlPoints.length; ++i) { const point = controlPoints[i]; this.controlPoints[i] = new Vector4(point.x, point.y, point.z, point.w); } } getPoint(t, optionalTarget) { const point = optionalTarget || new Vector3(); const u = this.knots[this.startKnot] + t * (this.knots[this.endKnot] - this.knots[this.startKnot]); const hpoint = calcBSplinePoint(this.degree, this.knots, this.controlPoints, u); if (hpoint.w != 1) hpoint.divideScalar(hpoint.w); return point.set(hpoint.x, hpoint.y, hpoint.z); } getTangent(t, optionalTarget) { const tangent = optionalTarget || new Vector3(); const u = this.knots[0] + t * (this.knots[this.knots.length - 1] - this.knots[0]); const ders = calcNURBSDerivatives(this.degree, this.knots, this.controlPoints, u, 1); tangent.copy(ders[1]).normalize(); return tangent; } }; //#endregion //#region node_modules/three-stdlib/loaders/FBXLoader.js var fbxTree; var connections; var sceneGraph; var FBXLoader = class extends Loader$1 { constructor(manager) { super(manager); } load(url, onLoad, onProgress, onError) { const scope = this; const path = scope.path === "" ? LoaderUtils.extractUrlBase(url) : scope.path; const loader = new FileLoader(this.manager); loader.setPath(scope.path); loader.setResponseType("arraybuffer"); loader.setRequestHeader(scope.requestHeader); loader.setWithCredentials(scope.withCredentials); loader.load(url, function(buffer) { try { onLoad(scope.parse(buffer, path)); } catch (e) { if (onError) onError(e); else console.error(e); scope.manager.itemError(url); } }, onProgress, onError); } parse(FBXBuffer, path) { if (isFbxFormatBinary(FBXBuffer)) fbxTree = new BinaryParser().parse(FBXBuffer); else { const FBXText = convertArrayBufferToString(FBXBuffer); if (!isFbxFormatASCII(FBXText)) throw new Error("THREE.FBXLoader: Unknown format."); if (getFbxVersion(FBXText) < 7e3) throw new Error("THREE.FBXLoader: FBX version not supported, FileVersion: " + getFbxVersion(FBXText)); fbxTree = new TextParser().parse(FBXText); } return new FBXTreeParser(new TextureLoader(this.manager).setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin), this.manager).parse(fbxTree); } }; var FBXTreeParser = class { constructor(textureLoader, manager) { this.textureLoader = textureLoader; this.manager = manager; } parse() { connections = this.parseConnections(); const images = this.parseImages(); const textures = this.parseTextures(images); const materials = this.parseMaterials(textures); const deformers = this.parseDeformers(); const geometryMap = new GeometryParser().parse(deformers); this.parseScene(deformers, geometryMap, materials); return sceneGraph; } parseConnections() { const connectionMap = /* @__PURE__ */ new Map(); if ("Connections" in fbxTree) fbxTree.Connections.connections.forEach(function(rawConnection) { const fromID = rawConnection[0]; const toID = rawConnection[1]; const relationship = rawConnection[2]; if (!connectionMap.has(fromID)) connectionMap.set(fromID, { parents: [], children: [] }); const parentRelationship = { ID: toID, relationship }; connectionMap.get(fromID).parents.push(parentRelationship); if (!connectionMap.has(toID)) connectionMap.set(toID, { parents: [], children: [] }); const childRelationship = { ID: fromID, relationship }; connectionMap.get(toID).children.push(childRelationship); }); return connectionMap; } parseImages() { const images = {}; const blobs = {}; if ("Video" in fbxTree.Objects) { const videoNodes = fbxTree.Objects.Video; for (const nodeID in videoNodes) { const videoNode = videoNodes[nodeID]; const id = parseInt(nodeID); images[id] = videoNode.RelativeFilename || videoNode.Filename; if ("Content" in videoNode) { const arrayBufferContent = videoNode.Content instanceof ArrayBuffer && videoNode.Content.byteLength > 0; const base64Content = typeof videoNode.Content === "string" && videoNode.Content !== ""; if (arrayBufferContent || base64Content) { const image = this.parseImage(videoNodes[nodeID]); blobs[videoNode.RelativeFilename || videoNode.Filename] = image; } } } } for (const id in images) { const filename = images[id]; if (blobs[filename] !== void 0) images[id] = blobs[filename]; else images[id] = images[id].split("\\").pop(); } return images; } parseImage(videoNode) { const content = videoNode.Content; const fileName = videoNode.RelativeFilename || videoNode.Filename; const extension = fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase(); let type; switch (extension) { case "bmp": type = "image/bmp"; break; case "jpg": case "jpeg": type = "image/jpeg"; break; case "png": type = "image/png"; break; case "tif": type = "image/tiff"; break; case "tga": if (this.manager.getHandler(".tga") === null) console.warn("FBXLoader: TGA loader not found, skipping ", fileName); type = "image/tga"; break; default: console.warn("FBXLoader: Image type \"" + extension + "\" is not supported."); return; } if (typeof content === "string") return "data:" + type + ";base64," + content; else { const array = new Uint8Array(content); return window.URL.createObjectURL(new Blob([array], { type })); } } parseTextures(images) { const textureMap = /* @__PURE__ */ new Map(); if ("Texture" in fbxTree.Objects) { const textureNodes = fbxTree.Objects.Texture; for (const nodeID in textureNodes) { const texture = this.parseTexture(textureNodes[nodeID], images); textureMap.set(parseInt(nodeID), texture); } } return textureMap; } parseTexture(textureNode, images) { const texture = this.loadTexture(textureNode, images); texture.ID = textureNode.id; texture.name = textureNode.attrName; const wrapModeU = textureNode.WrapModeU; const wrapModeV = textureNode.WrapModeV; const valueU = wrapModeU !== void 0 ? wrapModeU.value : 0; const valueV = wrapModeV !== void 0 ? wrapModeV.value : 0; texture.wrapS = valueU === 0 ? RepeatWrapping : ClampToEdgeWrapping; texture.wrapT = valueV === 0 ? RepeatWrapping : ClampToEdgeWrapping; if ("Scaling" in textureNode) { const values = textureNode.Scaling.value; texture.repeat.x = values[0]; texture.repeat.y = values[1]; } return texture; } loadTexture(textureNode, images) { let fileName; const currentPath = this.textureLoader.path; const children = connections.get(textureNode.id).children; if (children !== void 0 && children.length > 0 && images[children[0].ID] !== void 0) { fileName = images[children[0].ID]; if (fileName.indexOf("blob:") === 0 || fileName.indexOf("data:") === 0) this.textureLoader.setPath(void 0); } let texture; const extension = textureNode.FileName.slice(-3).toLowerCase(); if (extension === "tga") { const loader = this.manager.getHandler(".tga"); if (loader === null) { console.warn("FBXLoader: TGA loader not found, creating placeholder texture for", textureNode.RelativeFilename); texture = new Texture$1(); } else { loader.setPath(this.textureLoader.path); texture = loader.load(fileName); } } else if (extension === "psd") { console.warn("FBXLoader: PSD textures are not supported, creating placeholder texture for", textureNode.RelativeFilename); texture = new Texture$1(); } else texture = this.textureLoader.load(fileName); this.textureLoader.setPath(currentPath); return texture; } parseMaterials(textureMap) { const materialMap = /* @__PURE__ */ new Map(); if ("Material" in fbxTree.Objects) { const materialNodes = fbxTree.Objects.Material; for (const nodeID in materialNodes) { const material = this.parseMaterial(materialNodes[nodeID], textureMap); if (material !== null) materialMap.set(parseInt(nodeID), material); } } return materialMap; } parseMaterial(materialNode, textureMap) { const ID = materialNode.id; const name = materialNode.attrName; let type = materialNode.ShadingModel; if (typeof type === "object") type = type.value; if (!connections.has(ID)) return null; const parameters = this.parseParameters(materialNode, textureMap, ID); let material; switch (type.toLowerCase()) { case "phong": material = new MeshPhongMaterial(); break; case "lambert": material = new MeshLambertMaterial(); break; default: console.warn("THREE.FBXLoader: unknown material type \"%s\". Defaulting to MeshPhongMaterial.", type); material = new MeshPhongMaterial(); break; } material.setValues(parameters); material.name = name; return material; } parseParameters(materialNode, textureMap, ID) { const parameters = {}; if (materialNode.BumpFactor) parameters.bumpScale = materialNode.BumpFactor.value; if (materialNode.Diffuse) parameters.color = new Color().fromArray(materialNode.Diffuse.value); else if (materialNode.DiffuseColor && (materialNode.DiffuseColor.type === "Color" || materialNode.DiffuseColor.type === "ColorRGB")) parameters.color = new Color().fromArray(materialNode.DiffuseColor.value); if (materialNode.DisplacementFactor) parameters.displacementScale = materialNode.DisplacementFactor.value; if (materialNode.Emissive) parameters.emissive = new Color().fromArray(materialNode.Emissive.value); else if (materialNode.EmissiveColor && (materialNode.EmissiveColor.type === "Color" || materialNode.EmissiveColor.type === "ColorRGB")) parameters.emissive = new Color().fromArray(materialNode.EmissiveColor.value); if (materialNode.EmissiveFactor) parameters.emissiveIntensity = parseFloat(materialNode.EmissiveFactor.value); if (materialNode.Opacity) parameters.opacity = parseFloat(materialNode.Opacity.value); if (parameters.opacity < 1) parameters.transparent = true; if (materialNode.ReflectionFactor) parameters.reflectivity = materialNode.ReflectionFactor.value; if (materialNode.Shininess) parameters.shininess = materialNode.Shininess.value; if (materialNode.Specular) parameters.specular = new Color().fromArray(materialNode.Specular.value); else if (materialNode.SpecularColor && materialNode.SpecularColor.type === "Color") parameters.specular = new Color().fromArray(materialNode.SpecularColor.value); const scope = this; connections.get(ID).children.forEach(function(child) { const type = child.relationship; switch (type) { case "Bump": parameters.bumpMap = scope.getTexture(textureMap, child.ID); break; case "Maya|TEX_ao_map": parameters.aoMap = scope.getTexture(textureMap, child.ID); break; case "DiffuseColor": case "Maya|TEX_color_map": parameters.map = scope.getTexture(textureMap, child.ID); if (parameters.map !== void 0) if ("colorSpace" in parameters.map) parameters.map.colorSpace = "srgb"; else parameters.map.encoding = 3001; break; case "DisplacementColor": parameters.displacementMap = scope.getTexture(textureMap, child.ID); break; case "EmissiveColor": parameters.emissiveMap = scope.getTexture(textureMap, child.ID); if (parameters.emissiveMap !== void 0) if ("colorSpace" in parameters.emissiveMap) parameters.emissiveMap.colorSpace = "srgb"; else parameters.emissiveMap.encoding = 3001; break; case "NormalMap": case "Maya|TEX_normal_map": parameters.normalMap = scope.getTexture(textureMap, child.ID); break; case "ReflectionColor": parameters.envMap = scope.getTexture(textureMap, child.ID); if (parameters.envMap !== void 0) { parameters.envMap.mapping = 303; if ("colorSpace" in parameters.envMap) parameters.envMap.colorSpace = "srgb"; else parameters.envMap.encoding = 3001; } break; case "SpecularColor": parameters.specularMap = scope.getTexture(textureMap, child.ID); if (parameters.specularMap !== void 0) if ("colorSpace" in parameters.specularMap) parameters.specularMap.colorSpace = "srgb"; else parameters.specularMap.encoding = 3001; break; case "TransparentColor": case "TransparencyFactor": parameters.alphaMap = scope.getTexture(textureMap, child.ID); parameters.transparent = true; break; default: console.warn("THREE.FBXLoader: %s map is not supported in three.js, skipping texture.", type); break; } }); return parameters; } getTexture(textureMap, id) { if ("LayeredTexture" in fbxTree.Objects && id in fbxTree.Objects.LayeredTexture) { console.warn("THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer."); id = connections.get(id).children[0].ID; } return textureMap.get(id); } parseDeformers() { const skeletons = {}; const morphTargets = {}; if ("Deformer" in fbxTree.Objects) { const DeformerNodes = fbxTree.Objects.Deformer; for (const nodeID in DeformerNodes) { const deformerNode = DeformerNodes[nodeID]; const relationships = connections.get(parseInt(nodeID)); if (deformerNode.attrType === "Skin") { const skeleton = this.parseSkeleton(relationships, DeformerNodes); skeleton.ID = nodeID; if (relationships.parents.length > 1) console.warn("THREE.FBXLoader: skeleton attached to more than one geometry is not supported."); skeleton.geometryID = relationships.parents[0].ID; skeletons[nodeID] = skeleton; } else if (deformerNode.attrType === "BlendShape") { const morphTarget = { id: nodeID }; morphTarget.rawTargets = this.parseMorphTargets(relationships, DeformerNodes); morphTarget.id = nodeID; if (relationships.parents.length > 1) console.warn("THREE.FBXLoader: morph target attached to more than one geometry is not supported."); morphTargets[nodeID] = morphTarget; } } } return { skeletons, morphTargets }; } parseSkeleton(relationships, deformerNodes) { const rawBones = []; relationships.children.forEach(function(child) { const boneNode = deformerNodes[child.ID]; if (boneNode.attrType !== "Cluster") return; const rawBone = { ID: child.ID, indices: [], weights: [], transformLink: new Matrix4().fromArray(boneNode.TransformLink.a) }; if ("Indexes" in boneNode) { rawBone.indices = boneNode.Indexes.a; rawBone.weights = boneNode.Weights.a; } rawBones.push(rawBone); }); return { rawBones, bones: [] }; } parseMorphTargets(relationships, deformerNodes) { const rawMorphTargets = []; for (let i = 0; i < relationships.children.length; i++) { const child = relationships.children[i]; const morphTargetNode = deformerNodes[child.ID]; const rawMorphTarget = { name: morphTargetNode.attrName, initialWeight: morphTargetNode.DeformPercent, id: morphTargetNode.id, fullWeights: morphTargetNode.FullWeights.a }; if (morphTargetNode.attrType !== "BlendShapeChannel") return; rawMorphTarget.geoID = connections.get(parseInt(child.ID)).children.filter(function(child2) { return child2.relationship === void 0; })[0].ID; rawMorphTargets.push(rawMorphTarget); } return rawMorphTargets; } parseScene(deformers, geometryMap, materialMap) { sceneGraph = new Group(); const modelMap = this.parseModels(deformers.skeletons, geometryMap, materialMap); const modelNodes = fbxTree.Objects.Model; const scope = this; modelMap.forEach(function(model) { const modelNode = modelNodes[model.ID]; scope.setLookAtProperties(model, modelNode); connections.get(model.ID).parents.forEach(function(connection) { const parent = modelMap.get(connection.ID); if (parent !== void 0) parent.add(model); }); if (model.parent === null) sceneGraph.add(model); }); this.bindSkeleton(deformers.skeletons, geometryMap, modelMap); this.createAmbientLight(); sceneGraph.traverse(function(node) { if (node.userData.transformData) { if (node.parent) { node.userData.transformData.parentMatrix = node.parent.matrix; node.userData.transformData.parentMatrixWorld = node.parent.matrixWorld; } const transform = generateTransform(node.userData.transformData); node.applyMatrix4(transform); node.updateWorldMatrix(); } }); const animations = new AnimationParser().parse(); if (sceneGraph.children.length === 1 && sceneGraph.children[0].isGroup) { sceneGraph.children[0].animations = animations; sceneGraph = sceneGraph.children[0]; } sceneGraph.animations = animations; } parseModels(skeletons, geometryMap, materialMap) { const modelMap = /* @__PURE__ */ new Map(); const modelNodes = fbxTree.Objects.Model; for (const nodeID in modelNodes) { const id = parseInt(nodeID); const node = modelNodes[nodeID]; const relationships = connections.get(id); let model = this.buildSkeleton(relationships, skeletons, id, node.attrName); if (!model) { switch (node.attrType) { case "Camera": model = this.createCamera(relationships); break; case "Light": model = this.createLight(relationships); break; case "Mesh": model = this.createMesh(relationships, geometryMap, materialMap); break; case "NurbsCurve": model = this.createCurve(relationships, geometryMap); break; case "LimbNode": case "Root": model = new Bone(); break; default: model = new Group(); break; } model.name = node.attrName ? PropertyBinding.sanitizeNodeName(node.attrName) : ""; model.ID = id; } this.getTransformData(model, node); modelMap.set(id, model); } return modelMap; } buildSkeleton(relationships, skeletons, id, name) { let bone = null; relationships.parents.forEach(function(parent) { for (const ID in skeletons) { const skeleton = skeletons[ID]; skeleton.rawBones.forEach(function(rawBone, i) { if (rawBone.ID === parent.ID) { const subBone = bone; bone = new Bone(); bone.matrixWorld.copy(rawBone.transformLink); bone.name = name ? PropertyBinding.sanitizeNodeName(name) : ""; bone.ID = id; skeleton.bones[i] = bone; if (subBone !== null) bone.add(subBone); } }); } }); return bone; } createCamera(relationships) { let model; let cameraAttribute; relationships.children.forEach(function(child) { const attr = fbxTree.Objects.NodeAttribute[child.ID]; if (attr !== void 0) cameraAttribute = attr; }); if (cameraAttribute === void 0) model = new Object3D(); else { let type = 0; if (cameraAttribute.CameraProjectionType !== void 0 && cameraAttribute.CameraProjectionType.value === 1) type = 1; let nearClippingPlane = 1; if (cameraAttribute.NearPlane !== void 0) nearClippingPlane = cameraAttribute.NearPlane.value / 1e3; let farClippingPlane = 1e3; if (cameraAttribute.FarPlane !== void 0) farClippingPlane = cameraAttribute.FarPlane.value / 1e3; let width = window.innerWidth; let height = window.innerHeight; if (cameraAttribute.AspectWidth !== void 0 && cameraAttribute.AspectHeight !== void 0) { width = cameraAttribute.AspectWidth.value; height = cameraAttribute.AspectHeight.value; } const aspect = width / height; let fov = 45; if (cameraAttribute.FieldOfView !== void 0) fov = cameraAttribute.FieldOfView.value; const focalLength = cameraAttribute.FocalLength ? cameraAttribute.FocalLength.value : null; switch (type) { case 0: model = new PerspectiveCamera$1(fov, aspect, nearClippingPlane, farClippingPlane); if (focalLength !== null) model.setFocalLength(focalLength); break; case 1: model = new OrthographicCamera$1(-width / 2, width / 2, height / 2, -height / 2, nearClippingPlane, farClippingPlane); break; default: console.warn("THREE.FBXLoader: Unknown camera type " + type + "."); model = new Object3D(); break; } } return model; } createLight(relationships) { let model; let lightAttribute; relationships.children.forEach(function(child) { const attr = fbxTree.Objects.NodeAttribute[child.ID]; if (attr !== void 0) lightAttribute = attr; }); if (lightAttribute === void 0) model = new Object3D(); else { let type; if (lightAttribute.LightType === void 0) type = 0; else type = lightAttribute.LightType.value; let color = 16777215; if (lightAttribute.Color !== void 0) color = new Color().fromArray(lightAttribute.Color.value); let intensity = lightAttribute.Intensity === void 0 ? 1 : lightAttribute.Intensity.value / 100; if (lightAttribute.CastLightOnObject !== void 0 && lightAttribute.CastLightOnObject.value === 0) intensity = 0; let distance = 0; if (lightAttribute.FarAttenuationEnd !== void 0) if (lightAttribute.EnableFarAttenuation !== void 0 && lightAttribute.EnableFarAttenuation.value === 0) distance = 0; else distance = lightAttribute.FarAttenuationEnd.value; const decay = 1; switch (type) { case 0: model = new PointLight(color, intensity, distance, decay); break; case 1: model = new DirectionalLight(color, intensity); break; case 2: let angle = Math.PI / 3; if (lightAttribute.InnerAngle !== void 0) angle = MathUtils.degToRad(lightAttribute.InnerAngle.value); let penumbra = 0; if (lightAttribute.OuterAngle !== void 0) { penumbra = MathUtils.degToRad(lightAttribute.OuterAngle.value); penumbra = Math.max(penumbra, 1); } model = new SpotLight$1(color, intensity, distance, angle, penumbra, decay); break; default: console.warn("THREE.FBXLoader: Unknown light type " + lightAttribute.LightType.value + ", defaulting to a PointLight."); model = new PointLight(color, intensity); break; } if (lightAttribute.CastShadows !== void 0 && lightAttribute.CastShadows.value === 1) model.castShadow = true; } return model; } createMesh(relationships, geometryMap, materialMap) { let model; let geometry = null; let material = null; const materials = []; relationships.children.forEach(function(child) { if (geometryMap.has(child.ID)) geometry = geometryMap.get(child.ID); if (materialMap.has(child.ID)) materials.push(materialMap.get(child.ID)); }); if (materials.length > 1) material = materials; else if (materials.length > 0) material = materials[0]; else { material = new MeshPhongMaterial({ color: 13421772 }); materials.push(material); } if ("color" in geometry.attributes) materials.forEach(function(material2) { material2.vertexColors = true; }); if (geometry.FBX_Deformer) { model = new SkinnedMesh(geometry, material); model.normalizeSkinWeights(); } else model = new Mesh(geometry, material); return model; } createCurve(relationships, geometryMap) { return new Line$1(relationships.children.reduce(function(geo, child) { if (geometryMap.has(child.ID)) geo = geometryMap.get(child.ID); return geo; }, null), new LineBasicMaterial({ color: 3342591, linewidth: 1 })); } getTransformData(model, modelNode) { const transformData = {}; if ("InheritType" in modelNode) transformData.inheritType = parseInt(modelNode.InheritType.value); if ("RotationOrder" in modelNode) transformData.eulerOrder = getEulerOrder(modelNode.RotationOrder.value); else transformData.eulerOrder = "ZYX"; if ("Lcl_Translation" in modelNode) transformData.translation = modelNode.Lcl_Translation.value; if ("PreRotation" in modelNode) transformData.preRotation = modelNode.PreRotation.value; if ("Lcl_Rotation" in modelNode) transformData.rotation = modelNode.Lcl_Rotation.value; if ("PostRotation" in modelNode) transformData.postRotation = modelNode.PostRotation.value; if ("Lcl_Scaling" in modelNode) transformData.scale = modelNode.Lcl_Scaling.value; if ("ScalingOffset" in modelNode) transformData.scalingOffset = modelNode.ScalingOffset.value; if ("ScalingPivot" in modelNode) transformData.scalingPivot = modelNode.ScalingPivot.value; if ("RotationOffset" in modelNode) transformData.rotationOffset = modelNode.RotationOffset.value; if ("RotationPivot" in modelNode) transformData.rotationPivot = modelNode.RotationPivot.value; model.userData.transformData = transformData; } setLookAtProperties(model, modelNode) { if ("LookAtProperty" in modelNode) connections.get(model.ID).children.forEach(function(child) { if (child.relationship === "LookAtProperty") { const lookAtTarget = fbxTree.Objects.Model[child.ID]; if ("Lcl_Translation" in lookAtTarget) { const pos = lookAtTarget.Lcl_Translation.value; if (model.target !== void 0) { model.target.position.fromArray(pos); sceneGraph.add(model.target); } else model.lookAt(new Vector3().fromArray(pos)); } } }); } bindSkeleton(skeletons, geometryMap, modelMap) { const bindMatrices = this.parsePoseNodes(); for (const ID in skeletons) { const skeleton = skeletons[ID]; connections.get(parseInt(skeleton.ID)).parents.forEach(function(parent) { if (geometryMap.has(parent.ID)) { const geoID = parent.ID; connections.get(geoID).parents.forEach(function(geoConnParent) { if (modelMap.has(geoConnParent.ID)) modelMap.get(geoConnParent.ID).bind(new Skeleton(skeleton.bones), bindMatrices[geoConnParent.ID]); }); } }); } } parsePoseNodes() { const bindMatrices = {}; if ("Pose" in fbxTree.Objects) { const BindPoseNode = fbxTree.Objects.Pose; for (const nodeID in BindPoseNode) if (BindPoseNode[nodeID].attrType === "BindPose" && BindPoseNode[nodeID].NbPoseNodes > 0) { const poseNodes = BindPoseNode[nodeID].PoseNode; if (Array.isArray(poseNodes)) poseNodes.forEach(function(poseNode) { bindMatrices[poseNode.Node] = new Matrix4().fromArray(poseNode.Matrix.a); }); else bindMatrices[poseNodes.Node] = new Matrix4().fromArray(poseNodes.Matrix.a); } } return bindMatrices; } createAmbientLight() { if ("GlobalSettings" in fbxTree && "AmbientColor" in fbxTree.GlobalSettings) { const ambientColor = fbxTree.GlobalSettings.AmbientColor.value; const r = ambientColor[0]; const g = ambientColor[1]; const b = ambientColor[2]; if (r !== 0 || g !== 0 || b !== 0) { const color = new Color(r, g, b); sceneGraph.add(new AmbientLight(color, 1)); } } } }; var GeometryParser = class { parse(deformers) { const geometryMap = /* @__PURE__ */ new Map(); if ("Geometry" in fbxTree.Objects) { const geoNodes = fbxTree.Objects.Geometry; for (const nodeID in geoNodes) { const relationships = connections.get(parseInt(nodeID)); const geo = this.parseGeometry(relationships, geoNodes[nodeID], deformers); geometryMap.set(parseInt(nodeID), geo); } } return geometryMap; } parseGeometry(relationships, geoNode, deformers) { switch (geoNode.attrType) { case "Mesh": return this.parseMeshGeometry(relationships, geoNode, deformers); case "NurbsCurve": return this.parseNurbsGeometry(geoNode); } } parseMeshGeometry(relationships, geoNode, deformers) { const skeletons = deformers.skeletons; const morphTargets = []; const modelNodes = relationships.parents.map(function(parent) { return fbxTree.Objects.Model[parent.ID]; }); if (modelNodes.length === 0) return; const skeleton = relationships.children.reduce(function(skeleton2, child) { if (skeletons[child.ID] !== void 0) skeleton2 = skeletons[child.ID]; return skeleton2; }, null); relationships.children.forEach(function(child) { if (deformers.morphTargets[child.ID] !== void 0) morphTargets.push(deformers.morphTargets[child.ID]); }); const modelNode = modelNodes[0]; const transformData = {}; if ("RotationOrder" in modelNode) transformData.eulerOrder = getEulerOrder(modelNode.RotationOrder.value); if ("InheritType" in modelNode) transformData.inheritType = parseInt(modelNode.InheritType.value); if ("GeometricTranslation" in modelNode) transformData.translation = modelNode.GeometricTranslation.value; if ("GeometricRotation" in modelNode) transformData.rotation = modelNode.GeometricRotation.value; if ("GeometricScaling" in modelNode) transformData.scale = modelNode.GeometricScaling.value; const transform = generateTransform(transformData); return this.genGeometry(geoNode, skeleton, morphTargets, transform); } genGeometry(geoNode, skeleton, morphTargets, preTransform) { const geo = new BufferGeometry(); if (geoNode.attrName) geo.name = geoNode.attrName; const geoInfo = this.parseGeoNode(geoNode, skeleton); const buffers = this.genBuffers(geoInfo); const positionAttribute = new Float32BufferAttribute(buffers.vertex, 3); positionAttribute.applyMatrix4(preTransform); geo.setAttribute("position", positionAttribute); if (buffers.colors.length > 0) geo.setAttribute("color", new Float32BufferAttribute(buffers.colors, 3)); if (skeleton) { geo.setAttribute("skinIndex", new Uint16BufferAttribute(buffers.weightsIndices, 4)); geo.setAttribute("skinWeight", new Float32BufferAttribute(buffers.vertexWeights, 4)); geo.FBX_Deformer = skeleton; } if (buffers.normal.length > 0) { const normalMatrix = new Matrix3().getNormalMatrix(preTransform); const normalAttribute = new Float32BufferAttribute(buffers.normal, 3); normalAttribute.applyNormalMatrix(normalMatrix); geo.setAttribute("normal", normalAttribute); } buffers.uvs.forEach(function(uvBuffer, i) { if (UV1 === "uv2") i++; const name = i === 0 ? "uv" : `uv${i}`; geo.setAttribute(name, new Float32BufferAttribute(buffers.uvs[i], 2)); }); if (geoInfo.material && geoInfo.material.mappingType !== "AllSame") { let prevMaterialIndex = buffers.materialIndex[0]; let startIndex = 0; buffers.materialIndex.forEach(function(currentIndex, i) { if (currentIndex !== prevMaterialIndex) { geo.addGroup(startIndex, i - startIndex, prevMaterialIndex); prevMaterialIndex = currentIndex; startIndex = i; } }); if (geo.groups.length > 0) { const lastGroup = geo.groups[geo.groups.length - 1]; const lastIndex = lastGroup.start + lastGroup.count; if (lastIndex !== buffers.materialIndex.length) geo.addGroup(lastIndex, buffers.materialIndex.length - lastIndex, prevMaterialIndex); } if (geo.groups.length === 0) geo.addGroup(0, buffers.materialIndex.length, buffers.materialIndex[0]); } this.addMorphTargets(geo, geoNode, morphTargets, preTransform); return geo; } parseGeoNode(geoNode, skeleton) { const geoInfo = {}; geoInfo.vertexPositions = geoNode.Vertices !== void 0 ? geoNode.Vertices.a : []; geoInfo.vertexIndices = geoNode.PolygonVertexIndex !== void 0 ? geoNode.PolygonVertexIndex.a : []; if (geoNode.LayerElementColor) geoInfo.color = this.parseVertexColors(geoNode.LayerElementColor[0]); if (geoNode.LayerElementMaterial) geoInfo.material = this.parseMaterialIndices(geoNode.LayerElementMaterial[0]); if (geoNode.LayerElementNormal) geoInfo.normal = this.parseNormals(geoNode.LayerElementNormal[0]); if (geoNode.LayerElementUV) { geoInfo.uv = []; let i = 0; while (geoNode.LayerElementUV[i]) { if (geoNode.LayerElementUV[i].UV) geoInfo.uv.push(this.parseUVs(geoNode.LayerElementUV[i])); i++; } } geoInfo.weightTable = {}; if (skeleton !== null) { geoInfo.skeleton = skeleton; skeleton.rawBones.forEach(function(rawBone, i) { rawBone.indices.forEach(function(index, j) { if (geoInfo.weightTable[index] === void 0) geoInfo.weightTable[index] = []; geoInfo.weightTable[index].push({ id: i, weight: rawBone.weights[j] }); }); }); } return geoInfo; } genBuffers(geoInfo) { const buffers = { vertex: [], normal: [], colors: [], uvs: [], materialIndex: [], vertexWeights: [], weightsIndices: [] }; let polygonIndex = 0; let faceLength = 0; let displayedWeightsWarning = false; let facePositionIndexes = []; let faceNormals = []; let faceColors = []; let faceUVs = []; let faceWeights = []; let faceWeightIndices = []; const scope = this; geoInfo.vertexIndices.forEach(function(vertexIndex, polygonVertexIndex) { let materialIndex; let endOfFace = false; if (vertexIndex < 0) { vertexIndex = vertexIndex ^ -1; endOfFace = true; } let weightIndices = []; let weights = []; facePositionIndexes.push(vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2); if (geoInfo.color) { const data = getData(polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.color); faceColors.push(data[0], data[1], data[2]); } if (geoInfo.skeleton) { if (geoInfo.weightTable[vertexIndex] !== void 0) geoInfo.weightTable[vertexIndex].forEach(function(wt) { weights.push(wt.weight); weightIndices.push(wt.id); }); if (weights.length > 4) { if (!displayedWeightsWarning) { console.warn("THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights."); displayedWeightsWarning = true; } const wIndex = [ 0, 0, 0, 0 ]; const Weight = [ 0, 0, 0, 0 ]; weights.forEach(function(weight, weightIndex) { let currentWeight = weight; let currentIndex = weightIndices[weightIndex]; Weight.forEach(function(comparedWeight, comparedWeightIndex, comparedWeightArray) { if (currentWeight > comparedWeight) { comparedWeightArray[comparedWeightIndex] = currentWeight; currentWeight = comparedWeight; const tmp = wIndex[comparedWeightIndex]; wIndex[comparedWeightIndex] = currentIndex; currentIndex = tmp; } }); }); weightIndices = wIndex; weights = Weight; } while (weights.length < 4) { weights.push(0); weightIndices.push(0); } for (let i = 0; i < 4; ++i) { faceWeights.push(weights[i]); faceWeightIndices.push(weightIndices[i]); } } if (geoInfo.normal) { const data = getData(polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.normal); faceNormals.push(data[0], data[1], data[2]); } if (geoInfo.material && geoInfo.material.mappingType !== "AllSame") materialIndex = getData(polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.material)[0]; if (geoInfo.uv) geoInfo.uv.forEach(function(uv, i) { const data = getData(polygonVertexIndex, polygonIndex, vertexIndex, uv); if (faceUVs[i] === void 0) faceUVs[i] = []; faceUVs[i].push(data[0]); faceUVs[i].push(data[1]); }); faceLength++; if (endOfFace) { scope.genFace(buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength); polygonIndex++; faceLength = 0; facePositionIndexes = []; faceNormals = []; faceColors = []; faceUVs = []; faceWeights = []; faceWeightIndices = []; } }); return buffers; } genFace(buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength) { for (let i = 2; i < faceLength; i++) { buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[0]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[1]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[2]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[(i - 1) * 3]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[(i - 1) * 3 + 1]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[(i - 1) * 3 + 2]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[i * 3]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[i * 3 + 1]]); buffers.vertex.push(geoInfo.vertexPositions[facePositionIndexes[i * 3 + 2]]); if (geoInfo.skeleton) { buffers.vertexWeights.push(faceWeights[0]); buffers.vertexWeights.push(faceWeights[1]); buffers.vertexWeights.push(faceWeights[2]); buffers.vertexWeights.push(faceWeights[3]); buffers.vertexWeights.push(faceWeights[(i - 1) * 4]); buffers.vertexWeights.push(faceWeights[(i - 1) * 4 + 1]); buffers.vertexWeights.push(faceWeights[(i - 1) * 4 + 2]); buffers.vertexWeights.push(faceWeights[(i - 1) * 4 + 3]); buffers.vertexWeights.push(faceWeights[i * 4]); buffers.vertexWeights.push(faceWeights[i * 4 + 1]); buffers.vertexWeights.push(faceWeights[i * 4 + 2]); buffers.vertexWeights.push(faceWeights[i * 4 + 3]); buffers.weightsIndices.push(faceWeightIndices[0]); buffers.weightsIndices.push(faceWeightIndices[1]); buffers.weightsIndices.push(faceWeightIndices[2]); buffers.weightsIndices.push(faceWeightIndices[3]); buffers.weightsIndices.push(faceWeightIndices[(i - 1) * 4]); buffers.weightsIndices.push(faceWeightIndices[(i - 1) * 4 + 1]); buffers.weightsIndices.push(faceWeightIndices[(i - 1) * 4 + 2]); buffers.weightsIndices.push(faceWeightIndices[(i - 1) * 4 + 3]); buffers.weightsIndices.push(faceWeightIndices[i * 4]); buffers.weightsIndices.push(faceWeightIndices[i * 4 + 1]); buffers.weightsIndices.push(faceWeightIndices[i * 4 + 2]); buffers.weightsIndices.push(faceWeightIndices[i * 4 + 3]); } if (geoInfo.color) { buffers.colors.push(faceColors[0]); buffers.colors.push(faceColors[1]); buffers.colors.push(faceColors[2]); buffers.colors.push(faceColors[(i - 1) * 3]); buffers.colors.push(faceColors[(i - 1) * 3 + 1]); buffers.colors.push(faceColors[(i - 1) * 3 + 2]); buffers.colors.push(faceColors[i * 3]); buffers.colors.push(faceColors[i * 3 + 1]); buffers.colors.push(faceColors[i * 3 + 2]); } if (geoInfo.material && geoInfo.material.mappingType !== "AllSame") { buffers.materialIndex.push(materialIndex); buffers.materialIndex.push(materialIndex); buffers.materialIndex.push(materialIndex); } if (geoInfo.normal) { buffers.normal.push(faceNormals[0]); buffers.normal.push(faceNormals[1]); buffers.normal.push(faceNormals[2]); buffers.normal.push(faceNormals[(i - 1) * 3]); buffers.normal.push(faceNormals[(i - 1) * 3 + 1]); buffers.normal.push(faceNormals[(i - 1) * 3 + 2]); buffers.normal.push(faceNormals[i * 3]); buffers.normal.push(faceNormals[i * 3 + 1]); buffers.normal.push(faceNormals[i * 3 + 2]); } if (geoInfo.uv) geoInfo.uv.forEach(function(uv, j) { if (buffers.uvs[j] === void 0) buffers.uvs[j] = []; buffers.uvs[j].push(faceUVs[j][0]); buffers.uvs[j].push(faceUVs[j][1]); buffers.uvs[j].push(faceUVs[j][(i - 1) * 2]); buffers.uvs[j].push(faceUVs[j][(i - 1) * 2 + 1]); buffers.uvs[j].push(faceUVs[j][i * 2]); buffers.uvs[j].push(faceUVs[j][i * 2 + 1]); }); } } addMorphTargets(parentGeo, parentGeoNode, morphTargets, preTransform) { if (morphTargets.length === 0) return; parentGeo.morphTargetsRelative = true; parentGeo.morphAttributes.position = []; const scope = this; morphTargets.forEach(function(morphTarget) { morphTarget.rawTargets.forEach(function(rawTarget) { const morphGeoNode = fbxTree.Objects.Geometry[rawTarget.geoID]; if (morphGeoNode !== void 0) scope.genMorphGeometry(parentGeo, parentGeoNode, morphGeoNode, preTransform, rawTarget.name); }); }); } genMorphGeometry(parentGeo, parentGeoNode, morphGeoNode, preTransform, name) { const vertexIndices = parentGeoNode.PolygonVertexIndex !== void 0 ? parentGeoNode.PolygonVertexIndex.a : []; const morphPositionsSparse = morphGeoNode.Vertices !== void 0 ? morphGeoNode.Vertices.a : []; const indices = morphGeoNode.Indexes !== void 0 ? morphGeoNode.Indexes.a : []; const length = parentGeo.attributes.position.count * 3; const morphPositions = new Float32Array(length); for (let i = 0; i < indices.length; i++) { const morphIndex = indices[i] * 3; morphPositions[morphIndex] = morphPositionsSparse[i * 3]; morphPositions[morphIndex + 1] = morphPositionsSparse[i * 3 + 1]; morphPositions[morphIndex + 2] = morphPositionsSparse[i * 3 + 2]; } const morphGeoInfo = { vertexIndices, vertexPositions: morphPositions }; const positionAttribute = new Float32BufferAttribute(this.genBuffers(morphGeoInfo).vertex, 3); positionAttribute.name = name || morphGeoNode.attrName; positionAttribute.applyMatrix4(preTransform); parentGeo.morphAttributes.position.push(positionAttribute); } parseNormals(NormalNode) { const mappingType = NormalNode.MappingInformationType; const referenceType = NormalNode.ReferenceInformationType; const buffer = NormalNode.Normals.a; let indexBuffer = []; if (referenceType === "IndexToDirect") { if ("NormalIndex" in NormalNode) indexBuffer = NormalNode.NormalIndex.a; else if ("NormalsIndex" in NormalNode) indexBuffer = NormalNode.NormalsIndex.a; } return { dataSize: 3, buffer, indices: indexBuffer, mappingType, referenceType }; } parseUVs(UVNode) { const mappingType = UVNode.MappingInformationType; const referenceType = UVNode.ReferenceInformationType; const buffer = UVNode.UV.a; let indexBuffer = []; if (referenceType === "IndexToDirect") indexBuffer = UVNode.UVIndex.a; return { dataSize: 2, buffer, indices: indexBuffer, mappingType, referenceType }; } parseVertexColors(ColorNode) { const mappingType = ColorNode.MappingInformationType; const referenceType = ColorNode.ReferenceInformationType; const buffer = ColorNode.Colors.a; let indexBuffer = []; if (referenceType === "IndexToDirect") indexBuffer = ColorNode.ColorIndex.a; return { dataSize: 4, buffer, indices: indexBuffer, mappingType, referenceType }; } parseMaterialIndices(MaterialNode) { const mappingType = MaterialNode.MappingInformationType; const referenceType = MaterialNode.ReferenceInformationType; if (mappingType === "NoMappingInformation") return { dataSize: 1, buffer: [0], indices: [0], mappingType: "AllSame", referenceType }; const materialIndexBuffer = MaterialNode.Materials.a; const materialIndices = []; for (let i = 0; i < materialIndexBuffer.length; ++i) materialIndices.push(i); return { dataSize: 1, buffer: materialIndexBuffer, indices: materialIndices, mappingType, referenceType }; } parseNurbsGeometry(geoNode) { if (NURBSCurve === void 0) { console.error("THREE.FBXLoader: The loader relies on NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry."); return new BufferGeometry(); } const order = parseInt(geoNode.Order); if (isNaN(order)) { console.error("THREE.FBXLoader: Invalid Order %s given for geometry ID: %s", geoNode.Order, geoNode.id); return new BufferGeometry(); } const degree = order - 1; const knots = geoNode.KnotVector.a; const controlPoints = []; const pointsValues = geoNode.Points.a; for (let i = 0, l = pointsValues.length; i < l; i += 4) controlPoints.push(new Vector4().fromArray(pointsValues, i)); let startKnot, endKnot; if (geoNode.Form === "Closed") controlPoints.push(controlPoints[0]); else if (geoNode.Form === "Periodic") { startKnot = degree; endKnot = knots.length - 1 - startKnot; for (let i = 0; i < degree; ++i) controlPoints.push(controlPoints[i]); } const points = new NURBSCurve(degree, knots, controlPoints, startKnot, endKnot).getPoints(controlPoints.length * 12); return new BufferGeometry().setFromPoints(points); } }; var AnimationParser = class { parse() { const animationClips = []; const rawClips = this.parseClips(); if (rawClips !== void 0) for (const key in rawClips) { const rawClip = rawClips[key]; const clip = this.addClip(rawClip); animationClips.push(clip); } return animationClips; } parseClips() { if (fbxTree.Objects.AnimationCurve === void 0) return void 0; const curveNodesMap = this.parseAnimationCurveNodes(); this.parseAnimationCurves(curveNodesMap); const layersMap = this.parseAnimationLayers(curveNodesMap); return this.parseAnimStacks(layersMap); } parseAnimationCurveNodes() { const rawCurveNodes = fbxTree.Objects.AnimationCurveNode; const curveNodesMap = /* @__PURE__ */ new Map(); for (const nodeID in rawCurveNodes) { const rawCurveNode = rawCurveNodes[nodeID]; if (rawCurveNode.attrName.match(/S|R|T|DeformPercent/) !== null) { const curveNode = { id: rawCurveNode.id, attr: rawCurveNode.attrName, curves: {} }; curveNodesMap.set(curveNode.id, curveNode); } } return curveNodesMap; } parseAnimationCurves(curveNodesMap) { const rawCurves = fbxTree.Objects.AnimationCurve; for (const nodeID in rawCurves) { const animationCurve = { id: rawCurves[nodeID].id, times: rawCurves[nodeID].KeyTime.a.map(convertFBXTimeToSeconds), values: rawCurves[nodeID].KeyValueFloat.a }; const relationships = connections.get(animationCurve.id); if (relationships !== void 0) { const animationCurveID = relationships.parents[0].ID; const animationCurveRelationship = relationships.parents[0].relationship; if (animationCurveRelationship.match(/X/)) curveNodesMap.get(animationCurveID).curves["x"] = animationCurve; else if (animationCurveRelationship.match(/Y/)) curveNodesMap.get(animationCurveID).curves["y"] = animationCurve; else if (animationCurveRelationship.match(/Z/)) curveNodesMap.get(animationCurveID).curves["z"] = animationCurve; else if (animationCurveRelationship.match(/d|DeformPercent/) && curveNodesMap.has(animationCurveID)) curveNodesMap.get(animationCurveID).curves["morph"] = animationCurve; } } } parseAnimationLayers(curveNodesMap) { const rawLayers = fbxTree.Objects.AnimationLayer; const layersMap = /* @__PURE__ */ new Map(); for (const nodeID in rawLayers) { const layerCurveNodes = []; const connection = connections.get(parseInt(nodeID)); if (connection !== void 0) { connection.children.forEach(function(child, i) { if (curveNodesMap.has(child.ID)) { const curveNode = curveNodesMap.get(child.ID); if (curveNode.curves.x !== void 0 || curveNode.curves.y !== void 0 || curveNode.curves.z !== void 0) { if (layerCurveNodes[i] === void 0) { const modelID = connections.get(child.ID).parents.filter(function(parent) { return parent.relationship !== void 0; })[0].ID; if (modelID !== void 0) { const rawModel = fbxTree.Objects.Model[modelID.toString()]; if (rawModel === void 0) { console.warn("THREE.FBXLoader: Encountered a unused curve.", child); return; } const node = { modelName: rawModel.attrName ? PropertyBinding.sanitizeNodeName(rawModel.attrName) : "", ID: rawModel.id, initialPosition: [ 0, 0, 0 ], initialRotation: [ 0, 0, 0 ], initialScale: [ 1, 1, 1 ] }; sceneGraph.traverse(function(child2) { if (child2.ID === rawModel.id) { node.transform = child2.matrix; if (child2.userData.transformData) node.eulerOrder = child2.userData.transformData.eulerOrder; } }); if (!node.transform) node.transform = new Matrix4(); if ("PreRotation" in rawModel) node.preRotation = rawModel.PreRotation.value; if ("PostRotation" in rawModel) node.postRotation = rawModel.PostRotation.value; layerCurveNodes[i] = node; } } if (layerCurveNodes[i]) layerCurveNodes[i][curveNode.attr] = curveNode; } else if (curveNode.curves.morph !== void 0) { if (layerCurveNodes[i] === void 0) { const deformerID = connections.get(child.ID).parents.filter(function(parent) { return parent.relationship !== void 0; })[0].ID; const morpherID = connections.get(deformerID).parents[0].ID; const geoID = connections.get(morpherID).parents[0].ID; const modelID = connections.get(geoID).parents[0].ID; const rawModel = fbxTree.Objects.Model[modelID]; layerCurveNodes[i] = { modelName: rawModel.attrName ? PropertyBinding.sanitizeNodeName(rawModel.attrName) : "", morphName: fbxTree.Objects.Deformer[deformerID].attrName }; } layerCurveNodes[i][curveNode.attr] = curveNode; } } }); layersMap.set(parseInt(nodeID), layerCurveNodes); } } return layersMap; } parseAnimStacks(layersMap) { const rawStacks = fbxTree.Objects.AnimationStack; const rawClips = {}; for (const nodeID in rawStacks) { const children = connections.get(parseInt(nodeID)).children; if (children.length > 1) console.warn("THREE.FBXLoader: Encountered an animation stack with multiple layers, this is currently not supported. Ignoring subsequent layers."); const layer = layersMap.get(children[0].ID); rawClips[nodeID] = { name: rawStacks[nodeID].attrName, layer }; } return rawClips; } addClip(rawClip) { let tracks = []; const scope = this; rawClip.layer.forEach(function(rawTracks) { tracks = tracks.concat(scope.generateTracks(rawTracks)); }); return new AnimationClip(rawClip.name, -1, tracks); } generateTracks(rawTracks) { const tracks = []; let initialPosition = new Vector3(); let initialRotation = new Quaternion(); let initialScale = new Vector3(); if (rawTracks.transform) rawTracks.transform.decompose(initialPosition, initialRotation, initialScale); initialPosition = initialPosition.toArray(); initialRotation = new Euler().setFromQuaternion(initialRotation, rawTracks.eulerOrder).toArray(); initialScale = initialScale.toArray(); if (rawTracks.T !== void 0 && Object.keys(rawTracks.T.curves).length > 0) { const positionTrack = this.generateVectorTrack(rawTracks.modelName, rawTracks.T.curves, initialPosition, "position"); if (positionTrack !== void 0) tracks.push(positionTrack); } if (rawTracks.R !== void 0 && Object.keys(rawTracks.R.curves).length > 0) { const rotationTrack = this.generateRotationTrack(rawTracks.modelName, rawTracks.R.curves, initialRotation, rawTracks.preRotation, rawTracks.postRotation, rawTracks.eulerOrder); if (rotationTrack !== void 0) tracks.push(rotationTrack); } if (rawTracks.S !== void 0 && Object.keys(rawTracks.S.curves).length > 0) { const scaleTrack = this.generateVectorTrack(rawTracks.modelName, rawTracks.S.curves, initialScale, "scale"); if (scaleTrack !== void 0) tracks.push(scaleTrack); } if (rawTracks.DeformPercent !== void 0) { const morphTrack = this.generateMorphTrack(rawTracks); if (morphTrack !== void 0) tracks.push(morphTrack); } return tracks; } generateVectorTrack(modelName, curves, initialValue, type) { const times = this.getTimesForAllAxes(curves); const values = this.getKeyframeTrackValues(times, curves, initialValue); return new VectorKeyframeTrack(modelName + "." + type, times, values); } generateRotationTrack(modelName, curves, initialValue, preRotation, postRotation, eulerOrder) { if (curves.x !== void 0) { this.interpolateRotations(curves.x); curves.x.values = curves.x.values.map(MathUtils.degToRad); } if (curves.y !== void 0) { this.interpolateRotations(curves.y); curves.y.values = curves.y.values.map(MathUtils.degToRad); } if (curves.z !== void 0) { this.interpolateRotations(curves.z); curves.z.values = curves.z.values.map(MathUtils.degToRad); } const times = this.getTimesForAllAxes(curves); const values = this.getKeyframeTrackValues(times, curves, initialValue); if (preRotation !== void 0) { preRotation = preRotation.map(MathUtils.degToRad); preRotation.push(eulerOrder); preRotation = new Euler().fromArray(preRotation); preRotation = new Quaternion().setFromEuler(preRotation); } if (postRotation !== void 0) { postRotation = postRotation.map(MathUtils.degToRad); postRotation.push(eulerOrder); postRotation = new Euler().fromArray(postRotation); postRotation = new Quaternion().setFromEuler(postRotation).invert(); } const quaternion = new Quaternion(); const euler = new Euler(); const quaternionValues = []; for (let i = 0; i < values.length; i += 3) { euler.set(values[i], values[i + 1], values[i + 2], eulerOrder); quaternion.setFromEuler(euler); if (preRotation !== void 0) quaternion.premultiply(preRotation); if (postRotation !== void 0) quaternion.multiply(postRotation); quaternion.toArray(quaternionValues, i / 3 * 4); } return new QuaternionKeyframeTrack(modelName + ".quaternion", times, quaternionValues); } generateMorphTrack(rawTracks) { const curves = rawTracks.DeformPercent.curves.morph; const values = curves.values.map(function(val) { return val / 100; }); const morphNum = sceneGraph.getObjectByName(rawTracks.modelName).morphTargetDictionary[rawTracks.morphName]; return new NumberKeyframeTrack(rawTracks.modelName + ".morphTargetInfluences[" + morphNum + "]", curves.times, values); } getTimesForAllAxes(curves) { let times = []; if (curves.x !== void 0) times = times.concat(curves.x.times); if (curves.y !== void 0) times = times.concat(curves.y.times); if (curves.z !== void 0) times = times.concat(curves.z.times); times = times.sort(function(a, b) { return a - b; }); if (times.length > 1) { let targetIndex = 1; let lastValue = times[0]; for (let i = 1; i < times.length; i++) { const currentValue = times[i]; if (currentValue !== lastValue) { times[targetIndex] = currentValue; lastValue = currentValue; targetIndex++; } } times = times.slice(0, targetIndex); } return times; } getKeyframeTrackValues(times, curves, initialValue) { const prevValue = initialValue; const values = []; let xIndex = -1; let yIndex = -1; let zIndex = -1; times.forEach(function(time) { if (curves.x) xIndex = curves.x.times.indexOf(time); if (curves.y) yIndex = curves.y.times.indexOf(time); if (curves.z) zIndex = curves.z.times.indexOf(time); if (xIndex !== -1) { const xValue = curves.x.values[xIndex]; values.push(xValue); prevValue[0] = xValue; } else values.push(prevValue[0]); if (yIndex !== -1) { const yValue = curves.y.values[yIndex]; values.push(yValue); prevValue[1] = yValue; } else values.push(prevValue[1]); if (zIndex !== -1) { const zValue = curves.z.values[zIndex]; values.push(zValue); prevValue[2] = zValue; } else values.push(prevValue[2]); }); return values; } interpolateRotations(curve) { for (let i = 1; i < curve.values.length; i++) { const initialValue = curve.values[i - 1]; const valuesSpan = curve.values[i] - initialValue; const absoluteSpan = Math.abs(valuesSpan); if (absoluteSpan >= 180) { const numSubIntervals = absoluteSpan / 180; const step = valuesSpan / numSubIntervals; let nextValue = initialValue + step; const initialTime = curve.times[i - 1]; const interval = (curve.times[i] - initialTime) / numSubIntervals; let nextTime = initialTime + interval; const interpolatedTimes = []; const interpolatedValues = []; while (nextTime < curve.times[i]) { interpolatedTimes.push(nextTime); nextTime += interval; interpolatedValues.push(nextValue); nextValue += step; } curve.times = inject(curve.times, i, interpolatedTimes); curve.values = inject(curve.values, i, interpolatedValues); } } } }; var TextParser = class { getPrevNode() { return this.nodeStack[this.currentIndent - 2]; } getCurrentNode() { return this.nodeStack[this.currentIndent - 1]; } getCurrentProp() { return this.currentProp; } pushStack(node) { this.nodeStack.push(node); this.currentIndent += 1; } popStack() { this.nodeStack.pop(); this.currentIndent -= 1; } setCurrentProp(val, name) { this.currentProp = val; this.currentPropName = name; } parse(text) { this.currentIndent = 0; this.allNodes = new FBXTree(); this.nodeStack = []; this.currentProp = []; this.currentPropName = ""; const scope = this; const split = text.split(/[\r\n]+/); split.forEach(function(line, i) { const matchComment = line.match(/^[\s\t]*;/); const matchEmpty = line.match(/^[\s\t]*$/); if (matchComment || matchEmpty) return; const matchBeginning = line.match("^\\t{" + scope.currentIndent + "}(\\w+):(.*){", ""); const matchProperty = line.match("^\\t{" + scope.currentIndent + "}(\\w+):[\\s\\t\\r\\n](.*)"); const matchEnd = line.match("^\\t{" + (scope.currentIndent - 1) + "}}"); if (matchBeginning) scope.parseNodeBegin(line, matchBeginning); else if (matchProperty) scope.parseNodeProperty(line, matchProperty, split[++i]); else if (matchEnd) scope.popStack(); else if (line.match(/^[^\s\t}]/)) scope.parseNodePropertyContinued(line); }); return this.allNodes; } parseNodeBegin(line, property) { const nodeName = property[1].trim().replace(/^"/, "").replace(/"$/, ""); const nodeAttrs = property[2].split(",").map(function(attr) { return attr.trim().replace(/^"/, "").replace(/"$/, ""); }); const node = { name: nodeName }; const attrs = this.parseNodeAttr(nodeAttrs); const currentNode = this.getCurrentNode(); if (this.currentIndent === 0) this.allNodes.add(nodeName, node); else if (nodeName in currentNode) { if (nodeName === "PoseNode") currentNode.PoseNode.push(node); else if (currentNode[nodeName].id !== void 0) { currentNode[nodeName] = {}; currentNode[nodeName][currentNode[nodeName].id] = currentNode[nodeName]; } if (attrs.id !== "") currentNode[nodeName][attrs.id] = node; } else if (typeof attrs.id === "number") { currentNode[nodeName] = {}; currentNode[nodeName][attrs.id] = node; } else if (nodeName !== "Properties70") if (nodeName === "PoseNode") currentNode[nodeName] = [node]; else currentNode[nodeName] = node; if (typeof attrs.id === "number") node.id = attrs.id; if (attrs.name !== "") node.attrName = attrs.name; if (attrs.type !== "") node.attrType = attrs.type; this.pushStack(node); } parseNodeAttr(attrs) { let id = attrs[0]; if (attrs[0] !== "") { id = parseInt(attrs[0]); if (isNaN(id)) id = attrs[0]; } let name = "", type = ""; if (attrs.length > 1) { name = attrs[1].replace(/^(\w+)::/, ""); type = attrs[2]; } return { id, name, type }; } parseNodeProperty(line, property, contentLine) { let propName = property[1].replace(/^"/, "").replace(/"$/, "").trim(); let propValue = property[2].replace(/^"/, "").replace(/"$/, "").trim(); if (propName === "Content" && propValue === ",") propValue = contentLine.replace(/"/g, "").replace(/,$/, "").trim(); const currentNode = this.getCurrentNode(); if (currentNode.name === "Properties70") { this.parseNodeSpecialProperty(line, propName, propValue); return; } if (propName === "C") { const connProps = propValue.split(",").slice(1); const from = parseInt(connProps[0]); const to = parseInt(connProps[1]); let rest = propValue.split(",").slice(3); rest = rest.map(function(elem) { return elem.trim().replace(/^"/, ""); }); propName = "connections"; propValue = [from, to]; append(propValue, rest); if (currentNode[propName] === void 0) currentNode[propName] = []; } if (propName === "Node") currentNode.id = propValue; if (propName in currentNode && Array.isArray(currentNode[propName])) currentNode[propName].push(propValue); else if (propName !== "a") currentNode[propName] = propValue; else currentNode.a = propValue; this.setCurrentProp(currentNode, propName); if (propName === "a" && propValue.slice(-1) !== ",") currentNode.a = parseNumberArray(propValue); } parseNodePropertyContinued(line) { const currentNode = this.getCurrentNode(); currentNode.a += line; if (line.slice(-1) !== ",") currentNode.a = parseNumberArray(currentNode.a); } parseNodeSpecialProperty(line, propName, propValue) { const props = propValue.split("\",").map(function(prop) { return prop.trim().replace(/^\"/, "").replace(/\s/, "_"); }); const innerPropName = props[0]; const innerPropType1 = props[1]; const innerPropType2 = props[2]; const innerPropFlag = props[3]; let innerPropValue = props[4]; switch (innerPropType1) { case "int": case "enum": case "bool": case "ULongLong": case "double": case "Number": case "FieldOfView": innerPropValue = parseFloat(innerPropValue); break; case "Color": case "ColorRGB": case "Vector3D": case "Lcl_Translation": case "Lcl_Rotation": case "Lcl_Scaling": innerPropValue = parseNumberArray(innerPropValue); break; } this.getPrevNode()[innerPropName] = { type: innerPropType1, type2: innerPropType2, flag: innerPropFlag, value: innerPropValue }; this.setCurrentProp(this.getPrevNode(), innerPropName); } }; var BinaryParser = class { parse(buffer) { const reader = new BinaryReader(buffer); reader.skip(23); const version = reader.getUint32(); if (version < 6400) throw new Error("THREE.FBXLoader: FBX version not supported, FileVersion: " + version); const allNodes = new FBXTree(); while (!this.endOfContent(reader)) { const node = this.parseNode(reader, version); if (node !== null) allNodes.add(node.name, node); } return allNodes; } endOfContent(reader) { if (reader.size() % 16 === 0) return (reader.getOffset() + 160 + 16 & -16) >= reader.size(); else return reader.getOffset() + 160 + 16 >= reader.size(); } parseNode(reader, version) { const node = {}; const endOffset = version >= 7500 ? reader.getUint64() : reader.getUint32(); const numProperties = version >= 7500 ? reader.getUint64() : reader.getUint32(); version >= 7500 ? reader.getUint64() : reader.getUint32(); const nameLen = reader.getUint8(); const name = reader.getString(nameLen); if (endOffset === 0) return null; const propertyList = []; for (let i = 0; i < numProperties; i++) propertyList.push(this.parseProperty(reader)); const id = propertyList.length > 0 ? propertyList[0] : ""; const attrName = propertyList.length > 1 ? propertyList[1] : ""; const attrType = propertyList.length > 2 ? propertyList[2] : ""; node.singleProperty = numProperties === 1 && reader.getOffset() === endOffset ? true : false; while (endOffset > reader.getOffset()) { const subNode = this.parseNode(reader, version); if (subNode !== null) this.parseSubNode(name, node, subNode); } node.propertyList = propertyList; if (typeof id === "number") node.id = id; if (attrName !== "") node.attrName = attrName; if (attrType !== "") node.attrType = attrType; if (name !== "") node.name = name; return node; } parseSubNode(name, node, subNode) { if (subNode.singleProperty === true) { const value = subNode.propertyList[0]; if (Array.isArray(value)) { node[subNode.name] = subNode; subNode.a = value; } else node[subNode.name] = value; } else if (name === "Connections" && subNode.name === "C") { const array = []; subNode.propertyList.forEach(function(property, i) { if (i !== 0) array.push(property); }); if (node.connections === void 0) node.connections = []; node.connections.push(array); } else if (subNode.name === "Properties70") Object.keys(subNode).forEach(function(key) { node[key] = subNode[key]; }); else if (name === "Properties70" && subNode.name === "P") { let innerPropName = subNode.propertyList[0]; let innerPropType1 = subNode.propertyList[1]; const innerPropType2 = subNode.propertyList[2]; const innerPropFlag = subNode.propertyList[3]; let innerPropValue; if (innerPropName.indexOf("Lcl ") === 0) innerPropName = innerPropName.replace("Lcl ", "Lcl_"); if (innerPropType1.indexOf("Lcl ") === 0) innerPropType1 = innerPropType1.replace("Lcl ", "Lcl_"); if (innerPropType1 === "Color" || innerPropType1 === "ColorRGB" || innerPropType1 === "Vector" || innerPropType1 === "Vector3D" || innerPropType1.indexOf("Lcl_") === 0) innerPropValue = [ subNode.propertyList[4], subNode.propertyList[5], subNode.propertyList[6] ]; else innerPropValue = subNode.propertyList[4]; node[innerPropName] = { type: innerPropType1, type2: innerPropType2, flag: innerPropFlag, value: innerPropValue }; } else if (node[subNode.name] === void 0) if (typeof subNode.id === "number") { node[subNode.name] = {}; node[subNode.name][subNode.id] = subNode; } else node[subNode.name] = subNode; else if (subNode.name === "PoseNode") { if (!Array.isArray(node[subNode.name])) node[subNode.name] = [node[subNode.name]]; node[subNode.name].push(subNode); } else if (node[subNode.name][subNode.id] === void 0) node[subNode.name][subNode.id] = subNode; } parseProperty(reader) { const type = reader.getString(1); let length; switch (type) { case "C": return reader.getBoolean(); case "D": return reader.getFloat64(); case "F": return reader.getFloat32(); case "I": return reader.getInt32(); case "L": return reader.getInt64(); case "R": length = reader.getUint32(); return reader.getArrayBuffer(length); case "S": length = reader.getUint32(); return reader.getString(length); case "Y": return reader.getInt16(); case "b": case "c": case "d": case "f": case "i": case "l": const arrayLength = reader.getUint32(); const encoding = reader.getUint32(); const compressedLength = reader.getUint32(); if (encoding === 0) switch (type) { case "b": case "c": return reader.getBooleanArray(arrayLength); case "d": return reader.getFloat64Array(arrayLength); case "f": return reader.getFloat32Array(arrayLength); case "i": return reader.getInt32Array(arrayLength); case "l": return reader.getInt64Array(arrayLength); } const reader2 = new BinaryReader(unzlibSync(new Uint8Array(reader.getArrayBuffer(compressedLength))).buffer); switch (type) { case "b": case "c": return reader2.getBooleanArray(arrayLength); case "d": return reader2.getFloat64Array(arrayLength); case "f": return reader2.getFloat32Array(arrayLength); case "i": return reader2.getInt32Array(arrayLength); case "l": return reader2.getInt64Array(arrayLength); } default: throw new Error("THREE.FBXLoader: Unknown property type " + type); } } }; var BinaryReader = class { constructor(buffer, littleEndian) { this.dv = new DataView(buffer); this.offset = 0; this.littleEndian = littleEndian !== void 0 ? littleEndian : true; } getOffset() { return this.offset; } size() { return this.dv.buffer.byteLength; } skip(length) { this.offset += length; } getBoolean() { return (this.getUint8() & 1) === 1; } getBooleanArray(size) { const a = []; for (let i = 0; i < size; i++) a.push(this.getBoolean()); return a; } getUint8() { const value = this.dv.getUint8(this.offset); this.offset += 1; return value; } getInt16() { const value = this.dv.getInt16(this.offset, this.littleEndian); this.offset += 2; return value; } getInt32() { const value = this.dv.getInt32(this.offset, this.littleEndian); this.offset += 4; return value; } getInt32Array(size) { const a = []; for (let i = 0; i < size; i++) a.push(this.getInt32()); return a; } getUint32() { const value = this.dv.getUint32(this.offset, this.littleEndian); this.offset += 4; return value; } getInt64() { let low, high; if (this.littleEndian) { low = this.getUint32(); high = this.getUint32(); } else { high = this.getUint32(); low = this.getUint32(); } if (high & 2147483648) { high = ~high & 4294967295; low = ~low & 4294967295; if (low === 4294967295) high = high + 1 & 4294967295; low = low + 1 & 4294967295; return -(high * 4294967296 + low); } return high * 4294967296 + low; } getInt64Array(size) { const a = []; for (let i = 0; i < size; i++) a.push(this.getInt64()); return a; } getUint64() { let low, high; if (this.littleEndian) { low = this.getUint32(); high = this.getUint32(); } else { high = this.getUint32(); low = this.getUint32(); } return high * 4294967296 + low; } getFloat32() { const value = this.dv.getFloat32(this.offset, this.littleEndian); this.offset += 4; return value; } getFloat32Array(size) { const a = []; for (let i = 0; i < size; i++) a.push(this.getFloat32()); return a; } getFloat64() { const value = this.dv.getFloat64(this.offset, this.littleEndian); this.offset += 8; return value; } getFloat64Array(size) { const a = []; for (let i = 0; i < size; i++) a.push(this.getFloat64()); return a; } getArrayBuffer(size) { const value = this.dv.buffer.slice(this.offset, this.offset + size); this.offset += size; return value; } getString(size) { let a = []; for (let i = 0; i < size; i++) a[i] = this.getUint8(); const nullByte = a.indexOf(0); if (nullByte >= 0) a = a.slice(0, nullByte); return decodeText$1(new Uint8Array(a)); } }; var FBXTree = class { add(key, val) { this[key] = val; } }; function isFbxFormatBinary(buffer) { return buffer.byteLength >= 21 && "Kaydara FBX Binary \0" === convertArrayBufferToString(buffer, 0, 21); } function isFbxFormatASCII(text) { const CORRECT = [ "K", "a", "y", "d", "a", "r", "a", "\\", "F", "B", "X", "\\", "B", "i", "n", "a", "r", "y", "\\", "\\" ]; let cursor = 0; function read(offset) { const result = text[offset - 1]; text = text.slice(cursor + offset); cursor++; return result; } for (let i = 0; i < CORRECT.length; ++i) if (read(1) === CORRECT[i]) return false; return true; } function getFbxVersion(text) { const match = text.match(/FBXVersion: (\d+)/); if (match) return parseInt(match[1]); throw new Error("THREE.FBXLoader: Cannot find the version number for the file given."); } function convertFBXTimeToSeconds(time) { return time / 46186158e3; } var dataArray = []; function getData(polygonVertexIndex, polygonIndex, vertexIndex, infoObject) { let index; switch (infoObject.mappingType) { case "ByPolygonVertex": index = polygonVertexIndex; break; case "ByPolygon": index = polygonIndex; break; case "ByVertice": index = vertexIndex; break; case "AllSame": index = infoObject.indices[0]; break; default: console.warn("THREE.FBXLoader: unknown attribute mapping type " + infoObject.mappingType); } if (infoObject.referenceType === "IndexToDirect") index = infoObject.indices[index]; const from = index * infoObject.dataSize; const to = from + infoObject.dataSize; return slice(dataArray, infoObject.buffer, from, to); } var tempEuler = /* @__PURE__ */ new Euler(); var tempVec = /* @__PURE__ */ new Vector3(); function generateTransform(transformData) { const lTranslationM = new Matrix4(); const lPreRotationM = new Matrix4(); const lRotationM = new Matrix4(); const lPostRotationM = new Matrix4(); const lScalingM = new Matrix4(); const lScalingPivotM = new Matrix4(); const lScalingOffsetM = new Matrix4(); const lRotationOffsetM = new Matrix4(); const lRotationPivotM = new Matrix4(); const lParentGX = new Matrix4(); const lParentLX = new Matrix4(); const lGlobalT = new Matrix4(); const inheritType = transformData.inheritType ? transformData.inheritType : 0; if (transformData.translation) lTranslationM.setPosition(tempVec.fromArray(transformData.translation)); if (transformData.preRotation) { const array = transformData.preRotation.map(MathUtils.degToRad); array.push(transformData.eulerOrder); lPreRotationM.makeRotationFromEuler(tempEuler.fromArray(array)); } if (transformData.rotation) { const array = transformData.rotation.map(MathUtils.degToRad); array.push(transformData.eulerOrder); lRotationM.makeRotationFromEuler(tempEuler.fromArray(array)); } if (transformData.postRotation) { const array = transformData.postRotation.map(MathUtils.degToRad); array.push(transformData.eulerOrder); lPostRotationM.makeRotationFromEuler(tempEuler.fromArray(array)); lPostRotationM.invert(); } if (transformData.scale) lScalingM.scale(tempVec.fromArray(transformData.scale)); if (transformData.scalingOffset) lScalingOffsetM.setPosition(tempVec.fromArray(transformData.scalingOffset)); if (transformData.scalingPivot) lScalingPivotM.setPosition(tempVec.fromArray(transformData.scalingPivot)); if (transformData.rotationOffset) lRotationOffsetM.setPosition(tempVec.fromArray(transformData.rotationOffset)); if (transformData.rotationPivot) lRotationPivotM.setPosition(tempVec.fromArray(transformData.rotationPivot)); if (transformData.parentMatrixWorld) { lParentLX.copy(transformData.parentMatrix); lParentGX.copy(transformData.parentMatrixWorld); } const lLRM = lPreRotationM.clone().multiply(lRotationM).multiply(lPostRotationM); const lParentGRM = new Matrix4(); lParentGRM.extractRotation(lParentGX); const lParentTM = new Matrix4(); lParentTM.copyPosition(lParentGX); const lParentGRSM = lParentTM.clone().invert().multiply(lParentGX); const lParentGSM = lParentGRM.clone().invert().multiply(lParentGRSM); const lLSM = lScalingM; const lGlobalRS = new Matrix4(); if (inheritType === 0) lGlobalRS.copy(lParentGRM).multiply(lLRM).multiply(lParentGSM).multiply(lLSM); else if (inheritType === 1) lGlobalRS.copy(lParentGRM).multiply(lParentGSM).multiply(lLRM).multiply(lLSM); else { const lParentLSM_inv = new Matrix4().scale(new Vector3().setFromMatrixScale(lParentLX)).clone().invert(); const lParentGSM_noLocal = lParentGSM.clone().multiply(lParentLSM_inv); lGlobalRS.copy(lParentGRM).multiply(lLRM).multiply(lParentGSM_noLocal).multiply(lLSM); } const lRotationPivotM_inv = lRotationPivotM.clone().invert(); const lScalingPivotM_inv = lScalingPivotM.clone().invert(); let lTransform = lTranslationM.clone().multiply(lRotationOffsetM).multiply(lRotationPivotM).multiply(lPreRotationM).multiply(lRotationM).multiply(lPostRotationM).multiply(lRotationPivotM_inv).multiply(lScalingOffsetM).multiply(lScalingPivotM).multiply(lScalingM).multiply(lScalingPivotM_inv); const lLocalTWithAllPivotAndOffsetInfo = new Matrix4().copyPosition(lTransform); const lGlobalTranslation = lParentGX.clone().multiply(lLocalTWithAllPivotAndOffsetInfo); lGlobalT.copyPosition(lGlobalTranslation); lTransform = lGlobalT.clone().multiply(lGlobalRS); lTransform.premultiply(lParentGX.invert()); return lTransform; } function getEulerOrder(order) { order = order || 0; const enums = [ "ZYX", "YZX", "XZY", "ZXY", "YXZ", "XYZ" ]; if (order === 6) { console.warn("THREE.FBXLoader: unsupported Euler Order: Spherical XYZ. Animations and rotations may be incorrect."); return enums[0]; } return enums[order]; } function parseNumberArray(value) { return value.split(",").map(function(val) { return parseFloat(val); }); } function convertArrayBufferToString(buffer, from, to) { if (from === void 0) from = 0; if (to === void 0) to = buffer.byteLength; return decodeText$1(new Uint8Array(buffer, from, to)); } function append(a, b) { for (let i = 0, j = a.length, l = b.length; i < l; i++, j++) a[j] = b[i]; } function slice(a, b, from, to) { for (let i = from, j = 0; i < to; i++, j++) a[j] = b[i]; return a; } function inject(a1, index, a2) { return a1.slice(0, index).concat(a2).concat(a1.slice(index)); } //#endregion //#region node_modules/three-stdlib/loaders/FontLoader.js var __defProp$2 = Object.defineProperty; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$2 = (obj, key, value) => { __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var FontLoader = class extends Loader$1 { constructor(manager) { super(manager); } load(url, onLoad, onProgress, onError) { const loader = new FileLoader(this.manager); loader.setPath(this.path); loader.setRequestHeader(this.requestHeader); loader.setWithCredentials(this.withCredentials); loader.load(url, (response) => { if (typeof response !== "string") throw new Error("unsupported data type"); const json = JSON.parse(response); const font = this.parse(json); if (onLoad) onLoad(font); }, onProgress, onError); } loadAsync(url, onProgress) { return super.loadAsync(url, onProgress); } parse(json) { return new Font(json); } }; var Font = class { constructor(data) { __publicField$2(this, "data"); __publicField$2(this, "isFont", true); __publicField$2(this, "type", "Font"); this.data = data; } generateShapes(text, size = 100, _options) { const shapes = []; const options = { letterSpacing: 0, lineHeight: 1, ..._options }; const paths = createPaths(text, size, this.data, options); for (let p = 0, pl = paths.length; p < pl; p++) Array.prototype.push.apply(shapes, paths[p].toShapes(false)); return shapes; } }; function createPaths(text, size, data, options) { const chars = Array.from(text); const scale = size / data.resolution; const line_height = (data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness) * scale; const paths = []; let offsetX = 0, offsetY = 0; for (let i = 0; i < chars.length; i++) { const char = chars[i]; if (char === "\n") { offsetX = 0; offsetY -= line_height * options.lineHeight; } else { const ret = createPath(char, scale, offsetX, offsetY, data); if (ret) { offsetX += ret.offsetX + options.letterSpacing; paths.push(ret.path); } } } return paths; } function createPath(char, scale, offsetX, offsetY, data) { const glyph = data.glyphs[char] || data.glyphs["?"]; if (!glyph) { console.error("THREE.Font: character \"" + char + "\" does not exists in font family " + data.familyName + "."); return; } const path = new ShapePath(); let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; if (glyph.o) { const outline = glyph._cachedOutline || (glyph._cachedOutline = glyph.o.split(" ")); for (let i = 0, l = outline.length; i < l;) switch (outline[i++]) { case "m": x = parseInt(outline[i++]) * scale + offsetX; y = parseInt(outline[i++]) * scale + offsetY; path.moveTo(x, y); break; case "l": x = parseInt(outline[i++]) * scale + offsetX; y = parseInt(outline[i++]) * scale + offsetY; path.lineTo(x, y); break; case "q": cpx = parseInt(outline[i++]) * scale + offsetX; cpy = parseInt(outline[i++]) * scale + offsetY; cpx1 = parseInt(outline[i++]) * scale + offsetX; cpy1 = parseInt(outline[i++]) * scale + offsetY; path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); break; case "b": cpx = parseInt(outline[i++]) * scale + offsetX; cpy = parseInt(outline[i++]) * scale + offsetY; cpx1 = parseInt(outline[i++]) * scale + offsetX; cpy1 = parseInt(outline[i++]) * scale + offsetY; cpx2 = parseInt(outline[i++]) * scale + offsetX; cpy2 = parseInt(outline[i++]) * scale + offsetY; path.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, cpx, cpy); break; } } return { offsetX: glyph.ha * scale, path }; } //#endregion //#region node_modules/three-stdlib/_polyfill/Data3DTexture.js var Data3DTexture = class extends Texture$1 { constructor(data = null, width = 1, height = 1, depth = 1) { super(null); this.isData3DTexture = true; this.image = { data, width, height, depth }; this.magFilter = NearestFilter; this.minFilter = NearestFilter; this.wrapR = ClampToEdgeWrapping; this.generateMipmaps = false; this.flipY = false; this.unpackAlignment = 1; } }; //#endregion //#region node_modules/three-stdlib/utils/WorkerPool.js var WorkerPool = class { constructor(pool = 4) { this.pool = pool; this.queue = []; this.workers = []; this.workersResolve = []; this.workerStatus = 0; } _initWorker(workerId) { if (!this.workers[workerId]) { const worker = this.workerCreator(); worker.addEventListener("message", this._onMessage.bind(this, workerId)); this.workers[workerId] = worker; } } _getIdleWorker() { for (let i = 0; i < this.pool; i++) if (!(this.workerStatus & 1 << i)) return i; return -1; } _onMessage(workerId, msg) { const resolve = this.workersResolve[workerId]; resolve && resolve(msg); if (this.queue.length) { const { resolve: resolve2, msg: msg2, transfer } = this.queue.shift(); this.workersResolve[workerId] = resolve2; this.workers[workerId].postMessage(msg2, transfer); } else this.workerStatus ^= 1 << workerId; } setWorkerCreator(workerCreator) { this.workerCreator = workerCreator; } setWorkerLimit(pool) { this.pool = pool; } postMessage(msg, transfer) { return new Promise((resolve) => { const workerId = this._getIdleWorker(); if (workerId !== -1) { this._initWorker(workerId); this.workerStatus |= 1 << workerId; this.workersResolve[workerId] = resolve; this.workers[workerId].postMessage(msg, transfer); } else this.queue.push({ resolve, msg, transfer }); }); } dispose() { this.workers.forEach((worker) => worker.terminate()); this.workersResolve.length = 0; this.workers.length = 0; this.queue.length = 0; this.workerStatus = 0; } }; var KTX2Container = class { constructor() { this.vkFormat = 0; this.typeSize = 1; this.pixelWidth = 0; this.pixelHeight = 0; this.pixelDepth = 0; this.layerCount = 0; this.faceCount = 1; this.supercompressionScheme = 0; this.levels = []; this.dataFormatDescriptor = [{ vendorId: 0, descriptorType: 0, descriptorBlockSize: 0, versionNumber: 2, colorModel: 0, colorPrimaries: 1, transferFunction: 2, flags: 0, texelBlockDimension: [ 0, 0, 0, 0 ], bytesPlane: [ 0, 0, 0, 0, 0, 0, 0, 0 ], samples: [] }]; this.keyValue = {}; this.globalData = null; } }; var BufferReader = class { constructor(data, byteOffset, byteLength, littleEndian) { this._dataView = void 0; this._littleEndian = void 0; this._offset = void 0; this._dataView = new DataView(data.buffer, data.byteOffset + byteOffset, byteLength); this._littleEndian = littleEndian; this._offset = 0; } _nextUint8() { const value = this._dataView.getUint8(this._offset); this._offset += 1; return value; } _nextUint16() { const value = this._dataView.getUint16(this._offset, this._littleEndian); this._offset += 2; return value; } _nextUint32() { const value = this._dataView.getUint32(this._offset, this._littleEndian); this._offset += 4; return value; } _nextUint64() { const value = this._dataView.getUint32(this._offset, this._littleEndian) + 2 ** 32 * this._dataView.getUint32(this._offset + 4, this._littleEndian); this._offset += 8; return value; } _nextInt32() { const value = this._dataView.getInt32(this._offset, this._littleEndian); this._offset += 4; return value; } _nextUint8Array(len) { const value = new Uint8Array(this._dataView.buffer, this._dataView.byteOffset + this._offset, len); this._offset += len; return value; } _skip(bytes) { this._offset += bytes; return this; } _scan(maxByteLength, term) { if (term === void 0) term = 0; const byteOffset = this._offset; let byteLength = 0; while (this._dataView.getUint8(this._offset) !== term && byteLength < maxByteLength) { byteLength++; this._offset++; } if (byteLength < maxByteLength) this._offset++; return new Uint8Array(this._dataView.buffer, this._dataView.byteOffset + byteOffset, byteLength); } }; var KTX2_ID = [ 171, 75, 84, 88, 32, 50, 48, 187, 13, 10, 26, 10 ]; function decodeText(buffer) { if (typeof TextDecoder !== "undefined") return new TextDecoder().decode(buffer); return Buffer.from(buffer).toString("utf8"); } function read(data) { const id = new Uint8Array(data.buffer, data.byteOffset, KTX2_ID.length); if (id[0] !== KTX2_ID[0] || id[1] !== KTX2_ID[1] || id[2] !== KTX2_ID[2] || id[3] !== KTX2_ID[3] || id[4] !== KTX2_ID[4] || id[5] !== KTX2_ID[5] || id[6] !== KTX2_ID[6] || id[7] !== KTX2_ID[7] || id[8] !== KTX2_ID[8] || id[9] !== KTX2_ID[9] || id[10] !== KTX2_ID[10] || id[11] !== KTX2_ID[11]) throw new Error("Missing KTX 2.0 identifier."); const container = new KTX2Container(); const headerByteLength = 17 * Uint32Array.BYTES_PER_ELEMENT; const headerReader = new BufferReader(data, KTX2_ID.length, headerByteLength, true); container.vkFormat = headerReader._nextUint32(); container.typeSize = headerReader._nextUint32(); container.pixelWidth = headerReader._nextUint32(); container.pixelHeight = headerReader._nextUint32(); container.pixelDepth = headerReader._nextUint32(); container.layerCount = headerReader._nextUint32(); container.faceCount = headerReader._nextUint32(); const levelCount = headerReader._nextUint32(); container.supercompressionScheme = headerReader._nextUint32(); const dfdByteOffset = headerReader._nextUint32(); const dfdByteLength = headerReader._nextUint32(); const kvdByteOffset = headerReader._nextUint32(); const kvdByteLength = headerReader._nextUint32(); const sgdByteOffset = headerReader._nextUint64(); const sgdByteLength = headerReader._nextUint64(); const levelByteLength = levelCount * 3 * 8; const levelReader = new BufferReader(data, KTX2_ID.length + headerByteLength, levelByteLength, true); for (let i = 0; i < levelCount; i++) container.levels.push({ levelData: new Uint8Array(data.buffer, data.byteOffset + levelReader._nextUint64(), levelReader._nextUint64()), uncompressedByteLength: levelReader._nextUint64() }); const dfdReader = new BufferReader(data, dfdByteOffset, dfdByteLength, true); const dfd = { vendorId: dfdReader._skip(4)._nextUint16(), descriptorType: dfdReader._nextUint16(), versionNumber: dfdReader._nextUint16(), descriptorBlockSize: dfdReader._nextUint16(), colorModel: dfdReader._nextUint8(), colorPrimaries: dfdReader._nextUint8(), transferFunction: dfdReader._nextUint8(), flags: dfdReader._nextUint8(), texelBlockDimension: [ dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8() ], bytesPlane: [ dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8() ], samples: [] }; const numSamples = (dfd.descriptorBlockSize / 4 - 6) / 4; for (let i = 0; i < numSamples; i++) { const sample = { bitOffset: dfdReader._nextUint16(), bitLength: dfdReader._nextUint8(), channelType: dfdReader._nextUint8(), samplePosition: [ dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8(), dfdReader._nextUint8() ], sampleLower: -Infinity, sampleUpper: Infinity }; if (sample.channelType & 64) { sample.sampleLower = dfdReader._nextInt32(); sample.sampleUpper = dfdReader._nextInt32(); } else { sample.sampleLower = dfdReader._nextUint32(); sample.sampleUpper = dfdReader._nextUint32(); } dfd.samples[i] = sample; } container.dataFormatDescriptor.length = 0; container.dataFormatDescriptor.push(dfd); const kvdReader = new BufferReader(data, kvdByteOffset, kvdByteLength, true); while (kvdReader._offset < kvdByteLength) { const keyValueByteLength = kvdReader._nextUint32(); const keyData = kvdReader._scan(keyValueByteLength); const key = decodeText(keyData); container.keyValue[key] = kvdReader._nextUint8Array(keyValueByteLength - keyData.byteLength - 1); if (key.match(/^ktx/i)) { const text = decodeText(container.keyValue[key]); container.keyValue[key] = text.substring(0, text.lastIndexOf("\0")); } const kvPadding = keyValueByteLength % 4 ? 4 - keyValueByteLength % 4 : 0; kvdReader._skip(kvPadding); } if (sgdByteLength <= 0) return container; const sgdReader = new BufferReader(data, sgdByteOffset, sgdByteLength, true); const endpointCount = sgdReader._nextUint16(); const selectorCount = sgdReader._nextUint16(); const endpointsByteLength = sgdReader._nextUint32(); const selectorsByteLength = sgdReader._nextUint32(); const tablesByteLength = sgdReader._nextUint32(); const extendedByteLength = sgdReader._nextUint32(); const imageDescs = []; for (let i = 0; i < levelCount; i++) imageDescs.push({ imageFlags: sgdReader._nextUint32(), rgbSliceByteOffset: sgdReader._nextUint32(), rgbSliceByteLength: sgdReader._nextUint32(), alphaSliceByteOffset: sgdReader._nextUint32(), alphaSliceByteLength: sgdReader._nextUint32() }); const endpointsByteOffset = sgdByteOffset + sgdReader._offset; const selectorsByteOffset = endpointsByteOffset + endpointsByteLength; const tablesByteOffset = selectorsByteOffset + selectorsByteLength; const extendedByteOffset = tablesByteOffset + tablesByteLength; container.globalData = { endpointCount, selectorCount, imageDescs, endpointsData: new Uint8Array(data.buffer, data.byteOffset + endpointsByteOffset, endpointsByteLength), selectorsData: new Uint8Array(data.buffer, data.byteOffset + selectorsByteOffset, selectorsByteLength), tablesData: new Uint8Array(data.buffer, data.byteOffset + tablesByteOffset, tablesByteLength), extendedData: new Uint8Array(data.buffer, data.byteOffset + extendedByteOffset, extendedByteLength) }; return container; } //#endregion //#region node_modules/three-stdlib/libs/zstddec.js var init; var instance; var heap; var IMPORT_OBJECT = { env: { emscripten_notify_memory_growth: function(index) { heap = new Uint8Array(instance.exports.memory.buffer); } } }; var ZSTDDecoder = class { init() { if (init) return init; if (typeof fetch !== "undefined") init = fetch("data:application/wasm;base64," + wasm).then((response) => response.arrayBuffer()).then((arrayBuffer) => WebAssembly.instantiate(arrayBuffer, IMPORT_OBJECT)).then(this._init); else init = WebAssembly.instantiate(Buffer.from(wasm, "base64"), IMPORT_OBJECT).then(this._init); return init; } _init(result) { instance = result.instance; IMPORT_OBJECT.env.emscripten_notify_memory_growth(0); } decode(array, uncompressedSize = 0) { if (!instance) throw new Error(`ZSTDDecoder: Await .init() before decoding.`); const compressedSize = array.byteLength; const compressedPtr = instance.exports.malloc(compressedSize); heap.set(array, compressedPtr); uncompressedSize = uncompressedSize || Number(instance.exports.ZSTD_findDecompressedSize(compressedPtr, compressedSize)); const uncompressedPtr = instance.exports.malloc(uncompressedSize); const actualSize = instance.exports.ZSTD_decompress(uncompressedPtr, uncompressedSize, compressedPtr, compressedSize); const dec = heap.slice(uncompressedPtr, uncompressedPtr + actualSize); instance.exports.free(compressedPtr); instance.exports.free(uncompressedPtr); return dec; } }; var wasm = "AGFzbQEAAAABpQEVYAF/AX9gAn9/AGADf39/AX9gBX9/f39/AX9gAX8AYAJ/fwF/YAR/f39/AX9gA39/fwBgBn9/f39/fwF/YAd/f39/f39/AX9gAn9/AX5gAn5+AX5gAABgBX9/f39/AGAGf39/f39/AGAIf39/f39/f38AYAl/f39/f39/f38AYAABf2AIf39/f39/f38Bf2ANf39/f39/f39/f39/fwF/YAF/AX4CJwEDZW52H2Vtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgABANpaAEFAAAFAgEFCwACAQABAgIFBQcAAwABDgsBAQcAEhMHAAUBDAQEAAANBwQCAgYCBAgDAwMDBgEACQkHBgICAAYGAgQUBwYGAwIGAAMCAQgBBwUGCgoEEQAEBAEIAwgDBQgDEA8IAAcABAUBcAECAgUEAQCAAgYJAX8BQaCgwAILB2AHBm1lbW9yeQIABm1hbGxvYwAoBGZyZWUAJgxaU1REX2lzRXJyb3IAaBlaU1REX2ZpbmREZWNvbXByZXNzZWRTaXplAFQPWlNURF9kZWNvbXByZXNzAEoGX3N0YXJ0ACQJBwEAQQELASQKussBaA8AIAAgACgCBCABajYCBAsZACAAKAIAIAAoAgRBH3F0QQAgAWtBH3F2CwgAIABBiH9LC34BBH9BAyEBIAAoAgQiA0EgTQRAIAAoAggiASAAKAIQTwRAIAAQDQ8LIAAoAgwiAiABRgRAQQFBAiADQSBJGw8LIAAgASABIAJrIANBA3YiBCABIARrIAJJIgEbIgJrIgQ2AgggACADIAJBA3RrNgIEIAAgBCgAADYCAAsgAQsUAQF/IAAgARACIQIgACABEAEgAgv3AQECfyACRQRAIABCADcCACAAQQA2AhAgAEIANwIIQbh/DwsgACABNgIMIAAgAUEEajYCECACQQRPBEAgACABIAJqIgFBfGoiAzYCCCAAIAMoAAA2AgAgAUF/ai0AACIBBEAgAEEIIAEQFGs2AgQgAg8LIABBADYCBEF/DwsgACABNgIIIAAgAS0AACIDNgIAIAJBfmoiBEEBTQRAIARBAWtFBEAgACABLQACQRB0IANyIgM2AgALIAAgAS0AAUEIdCADajYCAAsgASACakF/ai0AACIBRQRAIABBADYCBEFsDwsgAEEoIAEQFCACQQN0ams2AgQgAgsWACAAIAEpAAA3AAAgACABKQAINwAICy8BAX8gAUECdEGgHWooAgAgACgCAEEgIAEgACgCBGprQR9xdnEhAiAAIAEQASACCyEAIAFCz9bTvtLHq9lCfiAAfEIfiUKHla+vmLbem55/fgsdAQF/IAAoAgggACgCDEYEfyAAKAIEQSBGBUEACwuCBAEDfyACQYDAAE8EQCAAIAEgAhBnIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAkEBSARAIAAhAgwBCyAAQQNxRQRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADTw0BIAJBA3ENAAsLAkAgA0F8cSIEQcAASQ0AIAIgBEFAaiIFSw0AA0AgAiABKAIANgIAIAIgASgCBDYCBCACIAEoAgg2AgggAiABKAIMNgIMIAIgASgCEDYCECACIAEoAhQ2AhQgAiABKAIYNgIYIAIgASgCHDYCHCACIAEoAiA2AiAgAiABKAIkNgIkIAIgASgCKDYCKCACIAEoAiw2AiwgAiABKAIwNgIwIAIgASgCNDYCNCACIAEoAjg2AjggAiABKAI8NgI8IAFBQGshASACQUBrIgIgBU0NAAsLIAIgBE8NAQNAIAIgASgCADYCACABQQRqIQEgAkEEaiICIARJDQALDAELIANBBEkEQCAAIQIMAQsgA0F8aiIEIABJBEAgACECDAELIAAhAgNAIAIgAS0AADoAACACIAEtAAE6AAEgAiABLQACOgACIAIgAS0AAzoAAyABQQRqIQEgAkEEaiICIARNDQALCyACIANJBEADQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADRw0ACwsgAAsMACAAIAEpAAA3AAALQQECfyAAKAIIIgEgACgCEEkEQEEDDwsgACAAKAIEIgJBB3E2AgQgACABIAJBA3ZrIgE2AgggACABKAAANgIAQQALDAAgACABKAIANgAAC/cCAQJ/AkAgACABRg0AAkAgASACaiAASwRAIAAgAmoiBCABSw0BCyAAIAEgAhALDwsgACABc0EDcSEDAkACQCAAIAFJBEAgAwRAIAAhAwwDCyAAQQNxRQRAIAAhAwwCCyAAIQMDQCACRQ0EIAMgAS0AADoAACABQQFqIQEgAkF/aiECIANBAWoiA0EDcQ0ACwwBCwJAIAMNACAEQQNxBEADQCACRQ0FIAAgAkF/aiICaiIDIAEgAmotAAA6AAAgA0EDcQ0ACwsgAkEDTQ0AA0AgACACQXxqIgJqIAEgAmooAgA2AgAgAkEDSw0ACwsgAkUNAgNAIAAgAkF/aiICaiABIAJqLQAAOgAAIAINAAsMAgsgAkEDTQ0AIAIhBANAIAMgASgCADYCACABQQRqIQEgA0EEaiEDIARBfGoiBEEDSw0ACyACQQNxIQILIAJFDQADQCADIAEtAAA6AAAgA0EBaiEDIAFBAWohASACQX9qIgINAAsLIAAL8wICAn8BfgJAIAJFDQAgACACaiIDQX9qIAE6AAAgACABOgAAIAJBA0kNACADQX5qIAE6AAAgACABOgABIANBfWogAToAACAAIAE6AAIgAkEHSQ0AIANBfGogAToAACAAIAE6AAMgAkEJSQ0AIABBACAAa0EDcSIEaiIDIAFB/wFxQYGChAhsIgE2AgAgAyACIARrQXxxIgRqIgJBfGogATYCACAEQQlJDQAgAyABNgIIIAMgATYCBCACQXhqIAE2AgAgAkF0aiABNgIAIARBGUkNACADIAE2AhggAyABNgIUIAMgATYCECADIAE2AgwgAkFwaiABNgIAIAJBbGogATYCACACQWhqIAE2AgAgAkFkaiABNgIAIAQgA0EEcUEYciIEayICQSBJDQAgAa0iBUIghiAFhCEFIAMgBGohAQNAIAEgBTcDGCABIAU3AxAgASAFNwMIIAEgBTcDACABQSBqIQEgAkFgaiICQR9LDQALCyAACy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAIajYCACADCy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAFajYCACADCx8AIAAgASACKAIEEAg2AgAgARAEGiAAIAJBCGo2AgQLCAAgAGdBH3MLugUBDX8jAEEQayIKJAACfyAEQQNNBEAgCkEANgIMIApBDGogAyAEEAsaIAAgASACIApBDGpBBBAVIgBBbCAAEAMbIAAgACAESxsMAQsgAEEAIAEoAgBBAXRBAmoQECENQVQgAygAACIGQQ9xIgBBCksNABogAiAAQQVqNgIAIAMgBGoiAkF8aiEMIAJBeWohDiACQXtqIRAgAEEGaiELQQQhBSAGQQR2IQRBICAAdCIAQQFyIQkgASgCACEPQQAhAiADIQYCQANAIAlBAkggAiAPS3JFBEAgAiEHAkAgCARAA0AgBEH//wNxQf//A0YEQCAHQRhqIQcgBiAQSQR/IAZBAmoiBigAACAFdgUgBUEQaiEFIARBEHYLIQQMAQsLA0AgBEEDcSIIQQNGBEAgBUECaiEFIARBAnYhBCAHQQNqIQcMAQsLIAcgCGoiByAPSw0EIAVBAmohBQNAIAIgB0kEQCANIAJBAXRqQQA7AQAgAkEBaiECDAELCyAGIA5LQQAgBiAFQQN1aiIHIAxLG0UEQCAHKAAAIAVBB3EiBXYhBAwCCyAEQQJ2IQQLIAYhBwsCfyALQX9qIAQgAEF/anEiBiAAQQF0QX9qIgggCWsiEUkNABogBCAIcSIEQQAgESAEIABIG2shBiALCyEIIA0gAkEBdGogBkF/aiIEOwEAIAlBASAGayAEIAZBAUgbayEJA0AgCSAASARAIABBAXUhACALQX9qIQsMAQsLAn8gByAOS0EAIAcgBSAIaiIFQQN1aiIGIAxLG0UEQCAFQQdxDAELIAUgDCIGIAdrQQN0awshBSACQQFqIQIgBEUhCCAGKAAAIAVBH3F2IQQMAQsLQWwgCUEBRyAFQSBKcg0BGiABIAJBf2o2AgAgBiAFQQdqQQN1aiADawwBC0FQCyEAIApBEGokACAACwkAQQFBBSAAGwsMACAAIAEoAAA2AAALqgMBCn8jAEHwAGsiCiQAIAJBAWohDiAAQQhqIQtBgIAEIAVBf2p0QRB1IQxBACECQQEhBkEBIAV0IglBf2oiDyEIA0AgAiAORkUEQAJAIAEgAkEBdCINai8BACIHQf//A0YEQCALIAhBA3RqIAI2AgQgCEF/aiEIQQEhBwwBCyAGQQAgDCAHQRB0QRB1ShshBgsgCiANaiAHOwEAIAJBAWohAgwBCwsgACAFNgIEIAAgBjYCACAJQQN2IAlBAXZqQQNqIQxBACEAQQAhBkEAIQIDQCAGIA5GBEADQAJAIAAgCUYNACAKIAsgAEEDdGoiASgCBCIGQQF0aiICIAIvAQAiAkEBajsBACABIAUgAhAUayIIOgADIAEgAiAIQf8BcXQgCWs7AQAgASAEIAZBAnQiAmooAgA6AAIgASACIANqKAIANgIEIABBAWohAAwBCwsFIAEgBkEBdGouAQAhDUEAIQcDQCAHIA1ORQRAIAsgAkEDdGogBjYCBANAIAIgDGogD3EiAiAISw0ACyAHQQFqIQcMAQsLIAZBAWohBgwBCwsgCkHwAGokAAsjAEIAIAEQCSAAhUKHla+vmLbem55/fkLj3MqV/M7y9YV/fAsQACAAQn43AwggACABNgIACyQBAX8gAARAIAEoAgQiAgRAIAEoAgggACACEQEADwsgABAmCwsfACAAIAEgAi8BABAINgIAIAEQBBogACACQQRqNgIEC0oBAX9BoCAoAgAiASAAaiIAQX9MBEBBiCBBMDYCAEF/DwsCQCAAPwBBEHRNDQAgABBmDQBBiCBBMDYCAEF/DwtBoCAgADYCACABC9cBAQh/Qbp/IQoCQCACKAIEIgggAigCACIJaiIOIAEgAGtLDQBBbCEKIAkgBCADKAIAIgtrSw0AIAAgCWoiBCACKAIIIgxrIQ0gACABQWBqIg8gCyAJQQAQKSADIAkgC2o2AgACQAJAIAwgBCAFa00EQCANIQUMAQsgDCAEIAZrSw0CIAcgDSAFayIAaiIBIAhqIAdNBEAgBCABIAgQDxoMAgsgBCABQQAgAGsQDyEBIAIgACAIaiIINgIEIAEgAGshBAsgBCAPIAUgCEEBECkLIA4hCgsgCgubAgEBfyMAQYABayINJAAgDSADNgJ8AkAgAkEDSwRAQX8hCQwBCwJAAkACQAJAIAJBAWsOAwADAgELIAZFBEBBuH8hCQwEC0FsIQkgBS0AACICIANLDQMgACAHIAJBAnQiAmooAgAgAiAIaigCABA7IAEgADYCAEEBIQkMAwsgASAJNgIAQQAhCQwCCyAKRQRAQWwhCQwCC0EAIQkgC0UgDEEZSHINAUEIIAR0QQhqIQBBACECA0AgAiAATw0CIAJBQGshAgwAAAsAC0FsIQkgDSANQfwAaiANQfgAaiAFIAYQFSICEAMNACANKAJ4IgMgBEsNACAAIA0gDSgCfCAHIAggAxAYIAEgADYCACACIQkLIA1BgAFqJAAgCQsLACAAIAEgAhALGgsQACAALwAAIAAtAAJBEHRyCy8AAn9BuH8gAUEISQ0AGkFyIAAoAAQiAEF3Sw0AGkG4fyAAQQhqIgAgACABSxsLCwkAIAAgATsAAAsDAAELigYBBX8gACAAKAIAIgVBfnE2AgBBACAAIAVBAXZqQYQgKAIAIgQgAEYbIQECQAJAIAAoAgQiAkUNACACKAIAIgNBAXENACACQQhqIgUgA0EBdkF4aiIDQQggA0EISxtnQR9zQQJ0QYAfaiIDKAIARgRAIAMgAigCDDYCAAsgAigCCCIDBEAgAyACKAIMNgIECyACKAIMIgMEQCADIAIoAgg2AgALIAIgAigCACAAKAIAQX5xajYCAEGEICEAAkACQCABRQ0AIAEgAjYCBCABKAIAIgNBAXENASADQQF2QXhqIgNBCCADQQhLG2dBH3NBAnRBgB9qIgMoAgAgAUEIakYEQCADIAEoAgw2AgALIAEoAggiAwRAIAMgASgCDDYCBAsgASgCDCIDBEAgAyABKAIINgIAQYQgKAIAIQQLIAIgAigCACABKAIAQX5xajYCACABIARGDQAgASABKAIAQQF2akEEaiEACyAAIAI2AgALIAIoAgBBAXZBeGoiAEEIIABBCEsbZ0Efc0ECdEGAH2oiASgCACEAIAEgBTYCACACIAA2AgwgAkEANgIIIABFDQEgACAFNgIADwsCQCABRQ0AIAEoAgAiAkEBcQ0AIAJBAXZBeGoiAkEIIAJBCEsbZ0Efc0ECdEGAH2oiAigCACABQQhqRgRAIAIgASgCDDYCAAsgASgCCCICBEAgAiABKAIMNgIECyABKAIMIgIEQCACIAEoAgg2AgBBhCAoAgAhBAsgACAAKAIAIAEoAgBBfnFqIgI2AgACQCABIARHBEAgASABKAIAQQF2aiAANgIEIAAoAgAhAgwBC0GEICAANgIACyACQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgIoAgAhASACIABBCGoiAjYCACAAIAE2AgwgAEEANgIIIAFFDQEgASACNgIADwsgBUEBdkF4aiIBQQggAUEISxtnQR9zQQJ0QYAfaiICKAIAIQEgAiAAQQhqIgI2AgAgACABNgIMIABBADYCCCABRQ0AIAEgAjYCAAsLDgAgAARAIABBeGoQJQsLgAIBA38CQCAAQQ9qQXhxQYQgKAIAKAIAQQF2ayICEB1Bf0YNAAJAQYQgKAIAIgAoAgAiAUEBcQ0AIAFBAXZBeGoiAUEIIAFBCEsbZ0Efc0ECdEGAH2oiASgCACAAQQhqRgRAIAEgACgCDDYCAAsgACgCCCIBBEAgASAAKAIMNgIECyAAKAIMIgFFDQAgASAAKAIINgIAC0EBIQEgACAAKAIAIAJBAXRqIgI2AgAgAkEBcQ0AIAJBAXZBeGoiAkEIIAJBCEsbZ0Efc0ECdEGAH2oiAygCACECIAMgAEEIaiIDNgIAIAAgAjYCDCAAQQA2AgggAkUNACACIAM2AgALIAELtwIBA38CQAJAIABBASAAGyICEDgiAA0AAkACQEGEICgCACIARQ0AIAAoAgAiA0EBcQ0AIAAgA0EBcjYCACADQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgEoAgAgAEEIakYEQCABIAAoAgw2AgALIAAoAggiAQRAIAEgACgCDDYCBAsgACgCDCIBBEAgASAAKAIINgIACyACECchAkEAIQFBhCAoAgAhACACDQEgACAAKAIAQX5xNgIAQQAPCyACQQ9qQXhxIgMQHSICQX9GDQIgAkEHakF4cSIAIAJHBEAgACACaxAdQX9GDQMLAkBBhCAoAgAiAUUEQEGAICAANgIADAELIAAgATYCBAtBhCAgADYCACAAIANBAXRBAXI2AgAMAQsgAEUNAQsgAEEIaiEBCyABC7kDAQJ/IAAgA2ohBQJAIANBB0wEQANAIAAgBU8NAiAAIAItAAA6AAAgAEEBaiEAIAJBAWohAgwAAAsACyAEQQFGBEACQCAAIAJrIgZBB00EQCAAIAItAAA6AAAgACACLQABOgABIAAgAi0AAjoAAiAAIAItAAM6AAMgAEEEaiACIAZBAnQiBkHAHmooAgBqIgIQFyACIAZB4B5qKAIAayECDAELIAAgAhAMCyACQQhqIQIgAEEIaiEACwJAAkACQAJAIAUgAU0EQCAAIANqIQEgBEEBRyAAIAJrQQ9Kcg0BA0AgACACEAwgAkEIaiECIABBCGoiACABSQ0ACwwFCyAAIAFLBEAgACEBDAQLIARBAUcgACACa0EPSnINASAAIQMgAiEEA0AgAyAEEAwgBEEIaiEEIANBCGoiAyABSQ0ACwwCCwNAIAAgAhAHIAJBEGohAiAAQRBqIgAgAUkNAAsMAwsgACEDIAIhBANAIAMgBBAHIARBEGohBCADQRBqIgMgAUkNAAsLIAIgASAAa2ohAgsDQCABIAVPDQEgASACLQAAOgAAIAFBAWohASACQQFqIQIMAAALAAsLQQECfyAAIAAoArjgASIDNgLE4AEgACgCvOABIQQgACABNgK84AEgACABIAJqNgK44AEgACABIAQgA2tqNgLA4AELpgEBAX8gACAAKALs4QEQFjYCyOABIABCADcD+OABIABCADcDuOABIABBwOABakIANwMAIABBqNAAaiIBQYyAgOAANgIAIABBADYCmOIBIABCADcDiOEBIABCAzcDgOEBIABBrNABakHgEikCADcCACAAQbTQAWpB6BIoAgA2AgAgACABNgIMIAAgAEGYIGo2AgggACAAQaAwajYCBCAAIABBEGo2AgALYQEBf0G4fyEDAkAgAUEDSQ0AIAIgABAhIgFBA3YiADYCCCACIAFBAXE2AgQgAiABQQF2QQNxIgM2AgACQCADQX9qIgFBAksNAAJAIAFBAWsOAgEAAgtBbA8LIAAhAwsgAwsMACAAIAEgAkEAEC4LiAQCA38CfiADEBYhBCAAQQBBKBAQIQAgBCACSwRAIAQPCyABRQRAQX8PCwJAAkAgA0EBRg0AIAEoAAAiBkGo6r5pRg0AQXYhAyAGQXBxQdDUtMIBRw0BQQghAyACQQhJDQEgAEEAQSgQECEAIAEoAAQhASAAQQE2AhQgACABrTcDAEEADwsgASACIAMQLyIDIAJLDQAgACADNgIYQXIhAyABIARqIgVBf2otAAAiAkEIcQ0AIAJBIHEiBkUEQEFwIQMgBS0AACIFQacBSw0BIAVBB3GtQgEgBUEDdkEKaq2GIgdCA4h+IAd8IQggBEEBaiEECyACQQZ2IQMgAkECdiEFAkAgAkEDcUF/aiICQQJLBEBBACECDAELAkACQAJAIAJBAWsOAgECAAsgASAEai0AACECIARBAWohBAwCCyABIARqLwAAIQIgBEECaiEEDAELIAEgBGooAAAhAiAEQQRqIQQLIAVBAXEhBQJ+AkACQAJAIANBf2oiA0ECTQRAIANBAWsOAgIDAQtCfyAGRQ0DGiABIARqMQAADAMLIAEgBGovAACtQoACfAwCCyABIARqKAAArQwBCyABIARqKQAACyEHIAAgBTYCICAAIAI2AhwgACAHNwMAQQAhAyAAQQA2AhQgACAHIAggBhsiBzcDCCAAIAdCgIAIIAdCgIAIVBs+AhALIAMLWwEBf0G4fyEDIAIQFiICIAFNBH8gACACakF/ai0AACIAQQNxQQJ0QaAeaigCACACaiAAQQZ2IgFBAnRBsB5qKAIAaiAAQSBxIgBFaiABRSAAQQV2cWoFQbh/CwsdACAAKAKQ4gEQWiAAQQA2AqDiASAAQgA3A5DiAQu1AwEFfyMAQZACayIKJABBuH8hBgJAIAVFDQAgBCwAACIIQf8BcSEHAkAgCEF/TARAIAdBgn9qQQF2IgggBU8NAkFsIQYgB0GBf2oiBUGAAk8NAiAEQQFqIQdBACEGA0AgBiAFTwRAIAUhBiAIIQcMAwUgACAGaiAHIAZBAXZqIgQtAABBBHY6AAAgACAGQQFyaiAELQAAQQ9xOgAAIAZBAmohBgwBCwAACwALIAcgBU8NASAAIARBAWogByAKEFMiBhADDQELIAYhBEEAIQYgAUEAQTQQECEJQQAhBQNAIAQgBkcEQCAAIAZqIggtAAAiAUELSwRAQWwhBgwDBSAJIAFBAnRqIgEgASgCAEEBajYCACAGQQFqIQZBASAILQAAdEEBdSAFaiEFDAILAAsLQWwhBiAFRQ0AIAUQFEEBaiIBQQxLDQAgAyABNgIAQQFBASABdCAFayIDEBQiAXQgA0cNACAAIARqIAFBAWoiADoAACAJIABBAnRqIgAgACgCAEEBajYCACAJKAIEIgBBAkkgAEEBcXINACACIARBAWo2AgAgB0EBaiEGCyAKQZACaiQAIAYLxhEBDH8jAEHwAGsiBSQAQWwhCwJAIANBCkkNACACLwAAIQogAi8AAiEJIAIvAAQhByAFQQhqIAQQDgJAIAMgByAJIApqakEGaiIMSQ0AIAUtAAohCCAFQdgAaiACQQZqIgIgChAGIgsQAw0BIAVBQGsgAiAKaiICIAkQBiILEAMNASAFQShqIAIgCWoiAiAHEAYiCxADDQEgBUEQaiACIAdqIAMgDGsQBiILEAMNASAAIAFqIg9BfWohECAEQQRqIQZBASELIAAgAUEDakECdiIDaiIMIANqIgIgA2oiDiEDIAIhBCAMIQcDQCALIAMgEElxBEAgACAGIAVB2ABqIAgQAkECdGoiCS8BADsAACAFQdgAaiAJLQACEAEgCS0AAyELIAcgBiAFQUBrIAgQAkECdGoiCS8BADsAACAFQUBrIAktAAIQASAJLQADIQogBCAGIAVBKGogCBACQQJ0aiIJLwEAOwAAIAVBKGogCS0AAhABIAktAAMhCSADIAYgBUEQaiAIEAJBAnRqIg0vAQA7AAAgBUEQaiANLQACEAEgDS0AAyENIAAgC2oiCyAGIAVB2ABqIAgQAkECdGoiAC8BADsAACAFQdgAaiAALQACEAEgAC0AAyEAIAcgCmoiCiAGIAVBQGsgCBACQQJ0aiIHLwEAOwAAIAVBQGsgBy0AAhABIActAAMhByAEIAlqIgkgBiAFQShqIAgQAkECdGoiBC8BADsAACAFQShqIAQtAAIQASAELQADIQQgAyANaiIDIAYgBUEQaiAIEAJBAnRqIg0vAQA7AAAgBUEQaiANLQACEAEgACALaiEAIAcgCmohByAEIAlqIQQgAyANLQADaiEDIAVB2ABqEA0gBUFAaxANciAFQShqEA1yIAVBEGoQDXJFIQsMAQsLIAQgDksgByACS3INAEFsIQsgACAMSw0BIAxBfWohCQNAQQAgACAJSSAFQdgAahAEGwRAIAAgBiAFQdgAaiAIEAJBAnRqIgovAQA7AAAgBUHYAGogCi0AAhABIAAgCi0AA2oiACAGIAVB2ABqIAgQAkECdGoiCi8BADsAACAFQdgAaiAKLQACEAEgACAKLQADaiEADAEFIAxBfmohCgNAIAVB2ABqEAQgACAKS3JFBEAgACAGIAVB2ABqIAgQAkECdGoiCS8BADsAACAFQdgAaiAJLQACEAEgACAJLQADaiEADAELCwNAIAAgCk0EQCAAIAYgBUHYAGogCBACQQJ0aiIJLwEAOwAAIAVB2ABqIAktAAIQASAAIAktAANqIQAMAQsLAkAgACAMTw0AIAAgBiAFQdgAaiAIEAIiAEECdGoiDC0AADoAACAMLQADQQFGBEAgBUHYAGogDC0AAhABDAELIAUoAlxBH0sNACAFQdgAaiAGIABBAnRqLQACEAEgBSgCXEEhSQ0AIAVBIDYCXAsgAkF9aiEMA0BBACAHIAxJIAVBQGsQBBsEQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiIAIAYgBUFAayAIEAJBAnRqIgcvAQA7AAAgBUFAayAHLQACEAEgACAHLQADaiEHDAEFIAJBfmohDANAIAVBQGsQBCAHIAxLckUEQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiEHDAELCwNAIAcgDE0EQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiEHDAELCwJAIAcgAk8NACAHIAYgBUFAayAIEAIiAEECdGoiAi0AADoAACACLQADQQFGBEAgBUFAayACLQACEAEMAQsgBSgCREEfSw0AIAVBQGsgBiAAQQJ0ai0AAhABIAUoAkRBIUkNACAFQSA2AkQLIA5BfWohAgNAQQAgBCACSSAFQShqEAQbBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2oiACAGIAVBKGogCBACQQJ0aiIELwEAOwAAIAVBKGogBC0AAhABIAAgBC0AA2ohBAwBBSAOQX5qIQIDQCAFQShqEAQgBCACS3JFBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2ohBAwBCwsDQCAEIAJNBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2ohBAwBCwsCQCAEIA5PDQAgBCAGIAVBKGogCBACIgBBAnRqIgItAAA6AAAgAi0AA0EBRgRAIAVBKGogAi0AAhABDAELIAUoAixBH0sNACAFQShqIAYgAEECdGotAAIQASAFKAIsQSFJDQAgBUEgNgIsCwNAQQAgAyAQSSAFQRBqEAQbBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2oiACAGIAVBEGogCBACQQJ0aiICLwEAOwAAIAVBEGogAi0AAhABIAAgAi0AA2ohAwwBBSAPQX5qIQIDQCAFQRBqEAQgAyACS3JFBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2ohAwwBCwsDQCADIAJNBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2ohAwwBCwsCQCADIA9PDQAgAyAGIAVBEGogCBACIgBBAnRqIgItAAA6AAAgAi0AA0EBRgRAIAVBEGogAi0AAhABDAELIAUoAhRBH0sNACAFQRBqIAYgAEECdGotAAIQASAFKAIUQSFJDQAgBUEgNgIUCyABQWwgBUHYAGoQCiAFQUBrEApxIAVBKGoQCnEgBUEQahAKcRshCwwJCwAACwALAAALAAsAAAsACwAACwALQWwhCwsgBUHwAGokACALC7UEAQ5/IwBBEGsiBiQAIAZBBGogABAOQVQhBQJAIARB3AtJDQAgBi0ABCEHIANB8ARqQQBB7AAQECEIIAdBDEsNACADQdwJaiIJIAggBkEIaiAGQQxqIAEgAhAxIhAQA0UEQCAGKAIMIgQgB0sNASADQdwFaiEPIANBpAVqIREgAEEEaiESIANBqAVqIQEgBCEFA0AgBSICQX9qIQUgCCACQQJ0aigCAEUNAAsgAkEBaiEOQQEhBQNAIAUgDk9FBEAgCCAFQQJ0IgtqKAIAIQwgASALaiAKNgIAIAVBAWohBSAKIAxqIQoMAQsLIAEgCjYCAEEAIQUgBigCCCELA0AgBSALRkUEQCABIAUgCWotAAAiDEECdGoiDSANKAIAIg1BAWo2AgAgDyANQQF0aiINIAw6AAEgDSAFOgAAIAVBAWohBQwBCwtBACEBIANBADYCqAUgBEF/cyAHaiEJQQEhBQNAIAUgDk9FBEAgCCAFQQJ0IgtqKAIAIQwgAyALaiABNgIAIAwgBSAJanQgAWohASAFQQFqIQUMAQsLIAcgBEEBaiIBIAJrIgRrQQFqIQgDQEEBIQUgBCAIT0UEQANAIAUgDk9FBEAgBUECdCIJIAMgBEE0bGpqIAMgCWooAgAgBHY2AgAgBUEBaiEFDAELCyAEQQFqIQQMAQsLIBIgByAPIAogESADIAIgARBkIAZBAToABSAGIAc6AAYgACAGKAIENgIACyAQIQULIAZBEGokACAFC8ENAQt/IwBB8ABrIgUkAEFsIQkCQCADQQpJDQAgAi8AACEKIAIvAAIhDCACLwAEIQYgBUEIaiAEEA4CQCADIAYgCiAMampBBmoiDUkNACAFLQAKIQcgBUHYAGogAkEGaiICIAoQBiIJEAMNASAFQUBrIAIgCmoiAiAMEAYiCRADDQEgBUEoaiACIAxqIgIgBhAGIgkQAw0BIAVBEGogAiAGaiADIA1rEAYiCRADDQEgACABaiIOQX1qIQ8gBEEEaiEGQQEhCSAAIAFBA2pBAnYiAmoiCiACaiIMIAJqIg0hAyAMIQQgCiECA0AgCSADIA9JcQRAIAYgBUHYAGogBxACQQF0aiIILQAAIQsgBUHYAGogCC0AARABIAAgCzoAACAGIAVBQGsgBxACQQF0aiIILQAAIQsgBUFAayAILQABEAEgAiALOgAAIAYgBUEoaiAHEAJBAXRqIggtAAAhCyAFQShqIAgtAAEQASAEIAs6AAAgBiAFQRBqIAcQAkEBdGoiCC0AACELIAVBEGogCC0AARABIAMgCzoAACAGIAVB2ABqIAcQAkEBdGoiCC0AACELIAVB2ABqIAgtAAEQASAAIAs6AAEgBiAFQUBrIAcQAkEBdGoiCC0AACELIAVBQGsgCC0AARABIAIgCzoAASAGIAVBKGogBxACQQF0aiIILQAAIQsgBUEoaiAILQABEAEgBCALOgABIAYgBUEQaiAHEAJBAXRqIggtAAAhCyAFQRBqIAgtAAEQASADIAs6AAEgA0ECaiEDIARBAmohBCACQQJqIQIgAEECaiEAIAkgBUHYAGoQDUVxIAVBQGsQDUVxIAVBKGoQDUVxIAVBEGoQDUVxIQkMAQsLIAQgDUsgAiAMS3INAEFsIQkgACAKSw0BIApBfWohCQNAIAVB2ABqEAQgACAJT3JFBEAgBiAFQdgAaiAHEAJBAXRqIggtAAAhCyAFQdgAaiAILQABEAEgACALOgAAIAYgBUHYAGogBxACQQF0aiIILQAAIQsgBUHYAGogCC0AARABIAAgCzoAASAAQQJqIQAMAQsLA0AgBUHYAGoQBCAAIApPckUEQCAGIAVB2ABqIAcQAkEBdGoiCS0AACEIIAVB2ABqIAktAAEQASAAIAg6AAAgAEEBaiEADAELCwNAIAAgCkkEQCAGIAVB2ABqIAcQAkEBdGoiCS0AACEIIAVB2ABqIAktAAEQASAAIAg6AAAgAEEBaiEADAELCyAMQX1qIQADQCAFQUBrEAQgAiAAT3JFBEAgBiAFQUBrIAcQAkEBdGoiCi0AACEJIAVBQGsgCi0AARABIAIgCToAACAGIAVBQGsgBxACQQF0aiIKLQAAIQkgBUFAayAKLQABEAEgAiAJOgABIAJBAmohAgwBCwsDQCAFQUBrEAQgAiAMT3JFBEAgBiAFQUBrIAcQAkEBdGoiAC0AACEKIAVBQGsgAC0AARABIAIgCjoAACACQQFqIQIMAQsLA0AgAiAMSQRAIAYgBUFAayAHEAJBAXRqIgAtAAAhCiAFQUBrIAAtAAEQASACIAo6AAAgAkEBaiECDAELCyANQX1qIQADQCAFQShqEAQgBCAAT3JFBEAgBiAFQShqIAcQAkEBdGoiAi0AACEKIAVBKGogAi0AARABIAQgCjoAACAGIAVBKGogBxACQQF0aiICLQAAIQogBUEoaiACLQABEAEgBCAKOgABIARBAmohBAwBCwsDQCAFQShqEAQgBCANT3JFBEAgBiAFQShqIAcQAkEBdGoiAC0AACECIAVBKGogAC0AARABIAQgAjoAACAEQQFqIQQMAQsLA0AgBCANSQRAIAYgBUEoaiAHEAJBAXRqIgAtAAAhAiAFQShqIAAtAAEQASAEIAI6AAAgBEEBaiEEDAELCwNAIAVBEGoQBCADIA9PckUEQCAGIAVBEGogBxACQQF0aiIALQAAIQIgBUEQaiAALQABEAEgAyACOgAAIAYgBUEQaiAHEAJBAXRqIgAtAAAhAiAFQRBqIAAtAAEQASADIAI6AAEgA0ECaiEDDAELCwNAIAVBEGoQBCADIA5PckUEQCAGIAVBEGogBxACQQF0aiIALQAAIQIgBUEQaiAALQABEAEgAyACOgAAIANBAWohAwwBCwsDQCADIA5JBEAgBiAFQRBqIAcQAkEBdGoiAC0AACECIAVBEGogAC0AARABIAMgAjoAACADQQFqIQMMAQsLIAFBbCAFQdgAahAKIAVBQGsQCnEgBUEoahAKcSAFQRBqEApxGyEJDAELQWwhCQsgBUHwAGokACAJC8oCAQR/IwBBIGsiBSQAIAUgBBAOIAUtAAIhByAFQQhqIAIgAxAGIgIQA0UEQCAEQQRqIQIgACABaiIDQX1qIQQDQCAFQQhqEAQgACAET3JFBEAgAiAFQQhqIAcQAkEBdGoiBi0AACEIIAVBCGogBi0AARABIAAgCDoAACACIAVBCGogBxACQQF0aiIGLQAAIQggBUEIaiAGLQABEAEgACAIOgABIABBAmohAAwBCwsDQCAFQQhqEAQgACADT3JFBEAgAiAFQQhqIAcQAkEBdGoiBC0AACEGIAVBCGogBC0AARABIAAgBjoAACAAQQFqIQAMAQsLA0AgACADT0UEQCACIAVBCGogBxACQQF0aiIELQAAIQYgBUEIaiAELQABEAEgACAGOgAAIABBAWohAAwBCwsgAUFsIAVBCGoQChshAgsgBUEgaiQAIAILtgMBCX8jAEEQayIGJAAgBkEANgIMIAZBADYCCEFUIQQCQAJAIANBQGsiDCADIAZBCGogBkEMaiABIAIQMSICEAMNACAGQQRqIAAQDiAGKAIMIgcgBi0ABEEBaksNASAAQQRqIQogBkEAOgAFIAYgBzoABiAAIAYoAgQ2AgAgB0EBaiEJQQEhBANAIAQgCUkEQCADIARBAnRqIgEoAgAhACABIAU2AgAgACAEQX9qdCAFaiEFIARBAWohBAwBCwsgB0EBaiEHQQAhBSAGKAIIIQkDQCAFIAlGDQEgAyAFIAxqLQAAIgRBAnRqIgBBASAEdEEBdSILIAAoAgAiAWoiADYCACAHIARrIQhBACEEAkAgC0EDTQRAA0AgBCALRg0CIAogASAEakEBdGoiACAIOgABIAAgBToAACAEQQFqIQQMAAALAAsDQCABIABPDQEgCiABQQF0aiIEIAg6AAEgBCAFOgAAIAQgCDoAAyAEIAU6AAIgBCAIOgAFIAQgBToABCAEIAg6AAcgBCAFOgAGIAFBBGohAQwAAAsACyAFQQFqIQUMAAALAAsgAiEECyAGQRBqJAAgBAutAQECfwJAQYQgKAIAIABHIAAoAgBBAXYiAyABa0F4aiICQXhxQQhHcgR/IAIFIAMQJ0UNASACQQhqC0EQSQ0AIAAgACgCACICQQFxIAAgAWpBD2pBeHEiASAAa0EBdHI2AgAgASAANgIEIAEgASgCAEEBcSAAIAJBAXZqIAFrIgJBAXRyNgIAQYQgIAEgAkH/////B3FqQQRqQYQgKAIAIABGGyABNgIAIAEQJQsLygIBBX8CQAJAAkAgAEEIIABBCEsbZ0EfcyAAaUEBR2oiAUEESSAAIAF2cg0AIAFBAnRB/B5qKAIAIgJFDQADQCACQXhqIgMoAgBBAXZBeGoiBSAATwRAIAIgBUEIIAVBCEsbZ0Efc0ECdEGAH2oiASgCAEYEQCABIAIoAgQ2AgALDAMLIARBHksNASAEQQFqIQQgAigCBCICDQALC0EAIQMgAUEgTw0BA0AgAUECdEGAH2ooAgAiAkUEQCABQR5LIQIgAUEBaiEBIAJFDQEMAwsLIAIgAkF4aiIDKAIAQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgEoAgBGBEAgASACKAIENgIACwsgAigCACIBBEAgASACKAIENgIECyACKAIEIgEEQCABIAIoAgA2AgALIAMgAygCAEEBcjYCACADIAAQNwsgAwvhCwINfwV+IwBB8ABrIgckACAHIAAoAvDhASIINgJcIAEgAmohDSAIIAAoAoDiAWohDwJAAkAgBUUEQCABIQQMAQsgACgCxOABIRAgACgCwOABIREgACgCvOABIQ4gAEEBNgKM4QFBACEIA0AgCEEDRwRAIAcgCEECdCICaiAAIAJqQazQAWooAgA2AkQgCEEBaiEIDAELC0FsIQwgB0EYaiADIAQQBhADDQEgB0EsaiAHQRhqIAAoAgAQEyAHQTRqIAdBGGogACgCCBATIAdBPGogB0EYaiAAKAIEEBMgDUFgaiESIAEhBEEAIQwDQCAHKAIwIAcoAixBA3RqKQIAIhRCEIinQf8BcSEIIAcoAkAgBygCPEEDdGopAgAiFUIQiKdB/wFxIQsgBygCOCAHKAI0QQN0aikCACIWQiCIpyEJIBVCIIghFyAUQiCIpyECAkAgFkIQiKdB/wFxIgNBAk8EQAJAIAZFIANBGUlyRQRAIAkgB0EYaiADQSAgBygCHGsiCiAKIANLGyIKEAUgAyAKayIDdGohCSAHQRhqEAQaIANFDQEgB0EYaiADEAUgCWohCQwBCyAHQRhqIAMQBSAJaiEJIAdBGGoQBBoLIAcpAkQhGCAHIAk2AkQgByAYNwNIDAELAkAgA0UEQCACBEAgBygCRCEJDAMLIAcoAkghCQwBCwJAAkAgB0EYakEBEAUgCSACRWpqIgNBA0YEQCAHKAJEQX9qIgMgA0VqIQkMAQsgA0ECdCAHaigCRCIJIAlFaiEJIANBAUYNAQsgByAHKAJINgJMCwsgByAHKAJENgJIIAcgCTYCRAsgF6chAyALBEAgB0EYaiALEAUgA2ohAwsgCCALakEUTwRAIAdBGGoQBBoLIAgEQCAHQRhqIAgQBSACaiECCyAHQRhqEAQaIAcgB0EYaiAUQhiIp0H/AXEQCCAUp0H//wNxajYCLCAHIAdBGGogFUIYiKdB/wFxEAggFadB//8DcWo2AjwgB0EYahAEGiAHIAdBGGogFkIYiKdB/wFxEAggFqdB//8DcWo2AjQgByACNgJgIAcoAlwhCiAHIAk2AmggByADNgJkAkACQAJAIAQgAiADaiILaiASSw0AIAIgCmoiEyAPSw0AIA0gBGsgC0Egak8NAQsgByAHKQNoNwMQIAcgBykDYDcDCCAEIA0gB0EIaiAHQdwAaiAPIA4gESAQEB4hCwwBCyACIARqIQggBCAKEAcgAkERTwRAIARBEGohAgNAIAIgCkEQaiIKEAcgAkEQaiICIAhJDQALCyAIIAlrIQIgByATNgJcIAkgCCAOa0sEQCAJIAggEWtLBEBBbCELDAILIBAgAiAOayICaiIKIANqIBBNBEAgCCAKIAMQDxoMAgsgCCAKQQAgAmsQDyEIIAcgAiADaiIDNgJkIAggAmshCCAOIQILIAlBEE8EQCADIAhqIQMDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALDAELAkAgCUEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgCUECdCIDQcAeaigCAGoiAhAXIAIgA0HgHmooAgBrIQIgBygCZCEDDAELIAggAhAMCyADQQlJDQAgAyAIaiEDIAhBCGoiCCACQQhqIgJrQQ9MBEADQCAIIAIQDCACQQhqIQIgCEEIaiIIIANJDQAMAgALAAsDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALCyAHQRhqEAQaIAsgDCALEAMiAhshDCAEIAQgC2ogAhshBCAFQX9qIgUNAAsgDBADDQFBbCEMIAdBGGoQBEECSQ0BQQAhCANAIAhBA0cEQCAAIAhBAnQiAmpBrNABaiACIAdqKAJENgIAIAhBAWohCAwBCwsgBygCXCEIC0G6fyEMIA8gCGsiACANIARrSw0AIAQEfyAEIAggABALIABqBUEACyABayEMCyAHQfAAaiQAIAwLkRcCFn8FfiMAQdABayIHJAAgByAAKALw4QEiCDYCvAEgASACaiESIAggACgCgOIBaiETAkACQCAFRQRAIAEhAwwBCyAAKALE4AEhESAAKALA4AEhFSAAKAK84AEhDyAAQQE2AozhAUEAIQgDQCAIQQNHBEAgByAIQQJ0IgJqIAAgAmpBrNABaigCADYCVCAIQQFqIQgMAQsLIAcgETYCZCAHIA82AmAgByABIA9rNgJoQWwhECAHQShqIAMgBBAGEAMNASAFQQQgBUEESBshFyAHQTxqIAdBKGogACgCABATIAdBxABqIAdBKGogACgCCBATIAdBzABqIAdBKGogACgCBBATQQAhBCAHQeAAaiEMIAdB5ABqIQoDQCAHQShqEARBAksgBCAXTnJFBEAgBygCQCAHKAI8QQN0aikCACIdQhCIp0H/AXEhCyAHKAJQIAcoAkxBA3RqKQIAIh5CEIinQf8BcSEJIAcoAkggBygCREEDdGopAgAiH0IgiKchCCAeQiCIISAgHUIgiKchAgJAIB9CEIinQf8BcSIDQQJPBEACQCAGRSADQRlJckUEQCAIIAdBKGogA0EgIAcoAixrIg0gDSADSxsiDRAFIAMgDWsiA3RqIQggB0EoahAEGiADRQ0BIAdBKGogAxAFIAhqIQgMAQsgB0EoaiADEAUgCGohCCAHQShqEAQaCyAHKQJUISEgByAINgJUIAcgITcDWAwBCwJAIANFBEAgAgRAIAcoAlQhCAwDCyAHKAJYIQgMAQsCQAJAIAdBKGpBARAFIAggAkVqaiIDQQNGBEAgBygCVEF/aiIDIANFaiEIDAELIANBAnQgB2ooAlQiCCAIRWohCCADQQFGDQELIAcgBygCWDYCXAsLIAcgBygCVDYCWCAHIAg2AlQLICCnIQMgCQRAIAdBKGogCRAFIANqIQMLIAkgC2pBFE8EQCAHQShqEAQaCyALBEAgB0EoaiALEAUgAmohAgsgB0EoahAEGiAHIAcoAmggAmoiCSADajYCaCAKIAwgCCAJSxsoAgAhDSAHIAdBKGogHUIYiKdB/wFxEAggHadB//8DcWo2AjwgByAHQShqIB5CGIinQf8BcRAIIB6nQf//A3FqNgJMIAdBKGoQBBogB0EoaiAfQhiIp0H/AXEQCCEOIAdB8ABqIARBBHRqIgsgCSANaiAIazYCDCALIAg2AgggCyADNgIEIAsgAjYCACAHIA4gH6dB//8DcWo2AkQgBEEBaiEEDAELCyAEIBdIDQEgEkFgaiEYIAdB4ABqIRogB0HkAGohGyABIQMDQCAHQShqEARBAksgBCAFTnJFBEAgBygCQCAHKAI8QQN0aikCACIdQhCIp0H/AXEhCyAHKAJQIAcoAkxBA3RqKQIAIh5CEIinQf8BcSEIIAcoAkggBygCREEDdGopAgAiH0IgiKchCSAeQiCIISAgHUIgiKchDAJAIB9CEIinQf8BcSICQQJPBEACQCAGRSACQRlJckUEQCAJIAdBKGogAkEgIAcoAixrIgogCiACSxsiChAFIAIgCmsiAnRqIQkgB0EoahAEGiACRQ0BIAdBKGogAhAFIAlqIQkMAQsgB0EoaiACEAUgCWohCSAHQShqEAQaCyAHKQJUISEgByAJNgJUIAcgITcDWAwBCwJAIAJFBEAgDARAIAcoAlQhCQwDCyAHKAJYIQkMAQsCQAJAIAdBKGpBARAFIAkgDEVqaiICQQNGBEAgBygCVEF/aiICIAJFaiEJDAELIAJBAnQgB2ooAlQiCSAJRWohCSACQQFGDQELIAcgBygCWDYCXAsLIAcgBygCVDYCWCAHIAk2AlQLICCnIRQgCARAIAdBKGogCBAFIBRqIRQLIAggC2pBFE8EQCAHQShqEAQaCyALBEAgB0EoaiALEAUgDGohDAsgB0EoahAEGiAHIAcoAmggDGoiGSAUajYCaCAbIBogCSAZSxsoAgAhHCAHIAdBKGogHUIYiKdB/wFxEAggHadB//8DcWo2AjwgByAHQShqIB5CGIinQf8BcRAIIB6nQf//A3FqNgJMIAdBKGoQBBogByAHQShqIB9CGIinQf8BcRAIIB+nQf//A3FqNgJEIAcgB0HwAGogBEEDcUEEdGoiDSkDCCIdNwPIASAHIA0pAwAiHjcDwAECQAJAAkAgBygCvAEiDiAepyICaiIWIBNLDQAgAyAHKALEASIKIAJqIgtqIBhLDQAgEiADayALQSBqTw0BCyAHIAcpA8gBNwMQIAcgBykDwAE3AwggAyASIAdBCGogB0G8AWogEyAPIBUgERAeIQsMAQsgAiADaiEIIAMgDhAHIAJBEU8EQCADQRBqIQIDQCACIA5BEGoiDhAHIAJBEGoiAiAISQ0ACwsgCCAdpyIOayECIAcgFjYCvAEgDiAIIA9rSwRAIA4gCCAVa0sEQEFsIQsMAgsgESACIA9rIgJqIhYgCmogEU0EQCAIIBYgChAPGgwCCyAIIBZBACACaxAPIQggByACIApqIgo2AsQBIAggAmshCCAPIQILIA5BEE8EQCAIIApqIQoDQCAIIAIQByACQRBqIQIgCEEQaiIIIApJDQALDAELAkAgDkEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgDkECdCIKQcAeaigCAGoiAhAXIAIgCkHgHmooAgBrIQIgBygCxAEhCgwBCyAIIAIQDAsgCkEJSQ0AIAggCmohCiAIQQhqIgggAkEIaiICa0EPTARAA0AgCCACEAwgAkEIaiECIAhBCGoiCCAKSQ0ADAIACwALA0AgCCACEAcgAkEQaiECIAhBEGoiCCAKSQ0ACwsgCxADBEAgCyEQDAQFIA0gDDYCACANIBkgHGogCWs2AgwgDSAJNgIIIA0gFDYCBCAEQQFqIQQgAyALaiEDDAILAAsLIAQgBUgNASAEIBdrIQtBACEEA0AgCyAFSARAIAcgB0HwAGogC0EDcUEEdGoiAikDCCIdNwPIASAHIAIpAwAiHjcDwAECQAJAAkAgBygCvAEiDCAepyICaiIKIBNLDQAgAyAHKALEASIJIAJqIhBqIBhLDQAgEiADayAQQSBqTw0BCyAHIAcpA8gBNwMgIAcgBykDwAE3AxggAyASIAdBGGogB0G8AWogEyAPIBUgERAeIRAMAQsgAiADaiEIIAMgDBAHIAJBEU8EQCADQRBqIQIDQCACIAxBEGoiDBAHIAJBEGoiAiAISQ0ACwsgCCAdpyIGayECIAcgCjYCvAEgBiAIIA9rSwRAIAYgCCAVa0sEQEFsIRAMAgsgESACIA9rIgJqIgwgCWogEU0EQCAIIAwgCRAPGgwCCyAIIAxBACACaxAPIQggByACIAlqIgk2AsQBIAggAmshCCAPIQILIAZBEE8EQCAIIAlqIQYDQCAIIAIQByACQRBqIQIgCEEQaiIIIAZJDQALDAELAkAgBkEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgBkECdCIGQcAeaigCAGoiAhAXIAIgBkHgHmooAgBrIQIgBygCxAEhCQwBCyAIIAIQDAsgCUEJSQ0AIAggCWohBiAIQQhqIgggAkEIaiICa0EPTARAA0AgCCACEAwgAkEIaiECIAhBCGoiCCAGSQ0ADAIACwALA0AgCCACEAcgAkEQaiECIAhBEGoiCCAGSQ0ACwsgEBADDQMgC0EBaiELIAMgEGohAwwBCwsDQCAEQQNHBEAgACAEQQJ0IgJqQazQAWogAiAHaigCVDYCACAEQQFqIQQMAQsLIAcoArwBIQgLQbp/IRAgEyAIayIAIBIgA2tLDQAgAwR/IAMgCCAAEAsgAGoFQQALIAFrIRALIAdB0AFqJAAgEAslACAAQgA3AgAgAEEAOwEIIABBADoACyAAIAE2AgwgACACOgAKC7QFAQN/IwBBMGsiBCQAIABB/wFqIgVBfWohBgJAIAMvAQIEQCAEQRhqIAEgAhAGIgIQAw0BIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahASOgAAIAMgBEEIaiAEQRhqEBI6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0FIAEgBEEQaiAEQRhqEBI6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBSABIARBCGogBEEYahASOgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEjoAACABIAJqIABrIQIMAwsgAyAEQRBqIARBGGoQEjoAAiADIARBCGogBEEYahASOgADIANBBGohAwwAAAsACyAEQRhqIAEgAhAGIgIQAw0AIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahAROgAAIAMgBEEIaiAEQRhqEBE6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0EIAEgBEEQaiAEQRhqEBE6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBCABIARBCGogBEEYahAROgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEToAACABIAJqIABrIQIMAgsgAyAEQRBqIARBGGoQEToAAiADIARBCGogBEEYahAROgADIANBBGohAwwAAAsACyAEQTBqJAAgAgtpAQF/An8CQAJAIAJBB00NACABKAAAQbfIwuF+Rw0AIAAgASgABDYCmOIBQWIgAEEQaiABIAIQPiIDEAMNAhogAEKBgICAEDcDiOEBIAAgASADaiACIANrECoMAQsgACABIAIQKgtBAAsLrQMBBn8jAEGAAWsiAyQAQWIhCAJAIAJBCUkNACAAQZjQAGogAUEIaiIEIAJBeGogAEGY0AAQMyIFEAMiBg0AIANBHzYCfCADIANB/ABqIANB+ABqIAQgBCAFaiAGGyIEIAEgAmoiAiAEaxAVIgUQAw0AIAMoAnwiBkEfSw0AIAMoAngiB0EJTw0AIABBiCBqIAMgBkGAC0GADCAHEBggA0E0NgJ8IAMgA0H8AGogA0H4AGogBCAFaiIEIAIgBGsQFSIFEAMNACADKAJ8IgZBNEsNACADKAJ4IgdBCk8NACAAQZAwaiADIAZBgA1B4A4gBxAYIANBIzYCfCADIANB/ABqIANB+ABqIAQgBWoiBCACIARrEBUiBRADDQAgAygCfCIGQSNLDQAgAygCeCIHQQpPDQAgACADIAZBwBBB0BEgBxAYIAQgBWoiBEEMaiIFIAJLDQAgAiAFayEFQQAhAgNAIAJBA0cEQCAEKAAAIgZBf2ogBU8NAiAAIAJBAnRqQZzQAWogBjYCACACQQFqIQIgBEEEaiEEDAELCyAEIAFrIQgLIANBgAFqJAAgCAtGAQN/IABBCGohAyAAKAIEIQJBACEAA0AgACACdkUEQCABIAMgAEEDdGotAAJBFktqIQEgAEEBaiEADAELCyABQQggAmt0C4YDAQV/Qbh/IQcCQCADRQ0AIAItAAAiBEUEQCABQQA2AgBBAUG4fyADQQFGGw8LAn8gAkEBaiIFIARBGHRBGHUiBkF/Sg0AGiAGQX9GBEAgA0EDSA0CIAUvAABBgP4BaiEEIAJBA2oMAQsgA0ECSA0BIAItAAEgBEEIdHJBgIB+aiEEIAJBAmoLIQUgASAENgIAIAVBAWoiASACIANqIgNLDQBBbCEHIABBEGogACAFLQAAIgVBBnZBI0EJIAEgAyABa0HAEEHQEUHwEiAAKAKM4QEgACgCnOIBIAQQHyIGEAMiCA0AIABBmCBqIABBCGogBUEEdkEDcUEfQQggASABIAZqIAgbIgEgAyABa0GAC0GADEGAFyAAKAKM4QEgACgCnOIBIAQQHyIGEAMiCA0AIABBoDBqIABBBGogBUECdkEDcUE0QQkgASABIAZqIAgbIgEgAyABa0GADUHgDkGQGSAAKAKM4QEgACgCnOIBIAQQHyIAEAMNACAAIAFqIAJrIQcLIAcLrQMBCn8jAEGABGsiCCQAAn9BUiACQf8BSw0AGkFUIANBDEsNABogAkEBaiELIABBBGohCUGAgAQgA0F/anRBEHUhCkEAIQJBASEEQQEgA3QiB0F/aiIMIQUDQCACIAtGRQRAAkAgASACQQF0Ig1qLwEAIgZB//8DRgRAIAkgBUECdGogAjoAAiAFQX9qIQVBASEGDAELIARBACAKIAZBEHRBEHVKGyEECyAIIA1qIAY7AQAgAkEBaiECDAELCyAAIAQ7AQIgACADOwEAIAdBA3YgB0EBdmpBA2ohBkEAIQRBACECA0AgBCALRkUEQCABIARBAXRqLgEAIQpBACEAA0AgACAKTkUEQCAJIAJBAnRqIAQ6AAIDQCACIAZqIAxxIgIgBUsNAAsgAEEBaiEADAELCyAEQQFqIQQMAQsLQX8gAg0AGkEAIQIDfyACIAdGBH9BAAUgCCAJIAJBAnRqIgAtAAJBAXRqIgEgAS8BACIBQQFqOwEAIAAgAyABEBRrIgU6AAMgACABIAVB/wFxdCAHazsBACACQQFqIQIMAQsLCyEFIAhBgARqJAAgBQvjBgEIf0FsIQcCQCACQQNJDQACQAJAAkACQCABLQAAIgNBA3EiCUEBaw4DAwEAAgsgACgCiOEBDQBBYg8LIAJBBUkNAkEDIQYgASgAACEFAn8CQAJAIANBAnZBA3EiCEF+aiIEQQFNBEAgBEEBaw0BDAILIAVBDnZB/wdxIQQgBUEEdkH/B3EhAyAIRQwCCyAFQRJ2IQRBBCEGIAVBBHZB//8AcSEDQQAMAQsgBUEEdkH//w9xIgNBgIAISw0DIAEtAARBCnQgBUEWdnIhBEEFIQZBAAshBSAEIAZqIgogAksNAgJAIANBgQZJDQAgACgCnOIBRQ0AQQAhAgNAIAJBg4ABSw0BIAJBQGshAgwAAAsACwJ/IAlBA0YEQCABIAZqIQEgAEHw4gFqIQIgACgCDCEGIAUEQCACIAMgASAEIAYQXwwCCyACIAMgASAEIAYQXQwBCyAAQbjQAWohAiABIAZqIQEgAEHw4gFqIQYgAEGo0ABqIQggBQRAIAggBiADIAEgBCACEF4MAQsgCCAGIAMgASAEIAIQXAsQAw0CIAAgAzYCgOIBIABBATYCiOEBIAAgAEHw4gFqNgLw4QEgCUECRgRAIAAgAEGo0ABqNgIMCyAAIANqIgBBiOMBakIANwAAIABBgOMBakIANwAAIABB+OIBakIANwAAIABB8OIBakIANwAAIAoPCwJ/AkACQAJAIANBAnZBA3FBf2oiBEECSw0AIARBAWsOAgACAQtBASEEIANBA3YMAgtBAiEEIAEvAABBBHYMAQtBAyEEIAEQIUEEdgsiAyAEaiIFQSBqIAJLBEAgBSACSw0CIABB8OIBaiABIARqIAMQCyEBIAAgAzYCgOIBIAAgATYC8OEBIAEgA2oiAEIANwAYIABCADcAECAAQgA3AAggAEIANwAAIAUPCyAAIAM2AoDiASAAIAEgBGo2AvDhASAFDwsCfwJAAkACQCADQQJ2QQNxQX9qIgRBAksNACAEQQFrDgIAAgELQQEhByADQQN2DAILQQIhByABLwAAQQR2DAELIAJBBEkgARAhIgJBj4CAAUtyDQFBAyEHIAJBBHYLIQIgAEHw4gFqIAEgB2otAAAgAkEgahAQIQEgACACNgKA4gEgACABNgLw4QEgB0EBaiEHCyAHC0sAIABC+erQ0OfJoeThADcDICAAQgA3AxggAELP1tO+0ser2UI3AxAgAELW64Lu6v2J9eAANwMIIABCADcDACAAQShqQQBBKBAQGgviAgICfwV+IABBKGoiASAAKAJIaiECAn4gACkDACIDQiBaBEAgACkDECIEQgeJIAApAwgiBUIBiXwgACkDGCIGQgyJfCAAKQMgIgdCEol8IAUQGSAEEBkgBhAZIAcQGQwBCyAAKQMYQsXP2bLx5brqJ3wLIAN8IQMDQCABQQhqIgAgAk0EQEIAIAEpAAAQCSADhUIbiUKHla+vmLbem55/fkLj3MqV/M7y9YV/fCEDIAAhAQwBCwsCQCABQQRqIgAgAksEQCABIQAMAQsgASgAAK1Ch5Wvr5i23puef34gA4VCF4lCz9bTvtLHq9lCfkL5893xmfaZqxZ8IQMLA0AgACACSQRAIAAxAABCxc/ZsvHluuonfiADhUILiUKHla+vmLbem55/fiEDIABBAWohAAwBCwsgA0IhiCADhULP1tO+0ser2UJ+IgNCHYggA4VC+fPd8Zn2masWfiIDQiCIIAOFC+8CAgJ/BH4gACAAKQMAIAKtfDcDAAJAAkAgACgCSCIDIAJqIgRBH00EQCABRQ0BIAAgA2pBKGogASACECAgACgCSCACaiEEDAELIAEgAmohAgJ/IAMEQCAAQShqIgQgA2ogAUEgIANrECAgACAAKQMIIAQpAAAQCTcDCCAAIAApAxAgACkAMBAJNwMQIAAgACkDGCAAKQA4EAk3AxggACAAKQMgIABBQGspAAAQCTcDICAAKAJIIQMgAEEANgJIIAEgA2tBIGohAQsgAUEgaiACTQsEQCACQWBqIQMgACkDICEFIAApAxghBiAAKQMQIQcgACkDCCEIA0AgCCABKQAAEAkhCCAHIAEpAAgQCSEHIAYgASkAEBAJIQYgBSABKQAYEAkhBSABQSBqIgEgA00NAAsgACAFNwMgIAAgBjcDGCAAIAc3AxAgACAINwMICyABIAJPDQEgAEEoaiABIAIgAWsiBBAgCyAAIAQ2AkgLCy8BAX8gAEUEQEG2f0EAIAMbDwtBun8hBCADIAFNBH8gACACIAMQEBogAwVBun8LCy8BAX8gAEUEQEG2f0EAIAMbDwtBun8hBCADIAFNBH8gACACIAMQCxogAwVBun8LC6gCAQZ/IwBBEGsiByQAIABB2OABaikDAEKAgIAQViEIQbh/IQUCQCAEQf//B0sNACAAIAMgBBBCIgUQAyIGDQAgACgCnOIBIQkgACAHQQxqIAMgAyAFaiAGGyIKIARBACAFIAYbayIGEEAiAxADBEAgAyEFDAELIAcoAgwhBCABRQRAQbp/IQUgBEEASg0BCyAGIANrIQUgAyAKaiEDAkAgCQRAIABBADYCnOIBDAELAkACQAJAIARBBUgNACAAQdjgAWopAwBCgICACFgNAAwBCyAAQQA2ApziAQwBCyAAKAIIED8hBiAAQQA2ApziASAGQRRPDQELIAAgASACIAMgBSAEIAgQOSEFDAELIAAgASACIAMgBSAEIAgQOiEFCyAHQRBqJAAgBQtnACAAQdDgAWogASACIAAoAuzhARAuIgEQAwRAIAEPC0G4fyECAkAgAQ0AIABB7OABaigCACIBBEBBYCECIAAoApjiASABRw0BC0EAIQIgAEHw4AFqKAIARQ0AIABBkOEBahBDCyACCycBAX8QVyIERQRAQUAPCyAEIAAgASACIAMgBBBLEE8hACAEEFYgAAs/AQF/AkACQAJAIAAoAqDiAUEBaiIBQQJLDQAgAUEBaw4CAAECCyAAEDBBAA8LIABBADYCoOIBCyAAKAKU4gELvAMCB38BfiMAQRBrIgkkAEG4fyEGAkAgBCgCACIIQQVBCSAAKALs4QEiBRtJDQAgAygCACIHQQFBBSAFGyAFEC8iBRADBEAgBSEGDAELIAggBUEDakkNACAAIAcgBRBJIgYQAw0AIAEgAmohCiAAQZDhAWohCyAIIAVrIQIgBSAHaiEHIAEhBQNAIAcgAiAJECwiBhADDQEgAkF9aiICIAZJBEBBuH8hBgwCCyAJKAIAIghBAksEQEFsIQYMAgsgB0EDaiEHAn8CQAJAAkAgCEEBaw4CAgABCyAAIAUgCiAFayAHIAYQSAwCCyAFIAogBWsgByAGEEcMAQsgBSAKIAVrIActAAAgCSgCCBBGCyIIEAMEQCAIIQYMAgsgACgC8OABBEAgCyAFIAgQRQsgAiAGayECIAYgB2ohByAFIAhqIQUgCSgCBEUNAAsgACkD0OABIgxCf1IEQEFsIQYgDCAFIAFrrFINAQsgACgC8OABBEBBaiEGIAJBBEkNASALEEQhDCAHKAAAIAynRw0BIAdBBGohByACQXxqIQILIAMgBzYCACAEIAI2AgAgBSABayEGCyAJQRBqJAAgBgsuACAAECsCf0EAQQAQAw0AGiABRSACRXJFBEBBYiAAIAEgAhA9EAMNARoLQQALCzcAIAEEQCAAIAAoAsTgASABKAIEIAEoAghqRzYCnOIBCyAAECtBABADIAFFckUEQCAAIAEQWwsL0QIBB38jAEEQayIGJAAgBiAENgIIIAYgAzYCDCAFBEAgBSgCBCEKIAUoAgghCQsgASEIAkACQANAIAAoAuzhARAWIQsCQANAIAQgC0kNASADKAAAQXBxQdDUtMIBRgRAIAMgBBAiIgcQAw0EIAQgB2shBCADIAdqIQMMAQsLIAYgAzYCDCAGIAQ2AggCQCAFBEAgACAFEE5BACEHQQAQA0UNAQwFCyAAIAogCRBNIgcQAw0ECyAAIAgQUCAMQQFHQQAgACAIIAIgBkEMaiAGQQhqEEwiByIDa0EAIAMQAxtBCkdyRQRAQbh/IQcMBAsgBxADDQMgAiAHayECIAcgCGohCEEBIQwgBigCDCEDIAYoAgghBAwBCwsgBiADNgIMIAYgBDYCCEG4fyEHIAQNASAIIAFrIQcMAQsgBiADNgIMIAYgBDYCCAsgBkEQaiQAIAcLRgECfyABIAAoArjgASICRwRAIAAgAjYCxOABIAAgATYCuOABIAAoArzgASEDIAAgATYCvOABIAAgASADIAJrajYCwOABCwutAgIEfwF+IwBBQGoiBCQAAkACQCACQQhJDQAgASgAAEFwcUHQ1LTCAUcNACABIAIQIiEBIABCADcDCCAAQQA2AgQgACABNgIADAELIARBGGogASACEC0iAxADBEAgACADEBoMAQsgAwRAIABBuH8QGgwBCyACIAQoAjAiA2shAiABIANqIQMDQAJAIAAgAyACIARBCGoQLCIFEAMEfyAFBSACIAVBA2oiBU8NAUG4fwsQGgwCCyAGQQFqIQYgAiAFayECIAMgBWohAyAEKAIMRQ0ACyAEKAI4BEAgAkEDTQRAIABBuH8QGgwCCyADQQRqIQMLIAQoAighAiAEKQMYIQcgAEEANgIEIAAgAyABazYCACAAIAIgBmytIAcgB0J/URs3AwgLIARBQGskAAslAQF/IwBBEGsiAiQAIAIgACABEFEgAigCACEAIAJBEGokACAAC30BBH8jAEGQBGsiBCQAIARB/wE2AggCQCAEQRBqIARBCGogBEEMaiABIAIQFSIGEAMEQCAGIQUMAQtBVCEFIAQoAgwiB0EGSw0AIAMgBEEQaiAEKAIIIAcQQSIFEAMNACAAIAEgBmogAiAGayADEDwhBQsgBEGQBGokACAFC4cBAgJ/An5BABAWIQMCQANAIAEgA08EQAJAIAAoAABBcHFB0NS0wgFGBEAgACABECIiAhADRQ0BQn4PCyAAIAEQVSIEQn1WDQMgBCAFfCIFIARUIQJCfiEEIAINAyAAIAEQUiICEAMNAwsgASACayEBIAAgAmohAAwBCwtCfiAFIAEbIQQLIAQLPwIBfwF+IwBBMGsiAiQAAn5CfiACQQhqIAAgARAtDQAaQgAgAigCHEEBRg0AGiACKQMICyEDIAJBMGokACADC40BAQJ/IwBBMGsiASQAAkAgAEUNACAAKAKI4gENACABIABB/OEBaigCADYCKCABIAApAvThATcDICAAEDAgACgCqOIBIQIgASABKAIoNgIYIAEgASkDIDcDECACIAFBEGoQGyAAQQA2AqjiASABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALKgECfyMAQRBrIgAkACAAQQA2AgggAEIANwMAIAAQWCEBIABBEGokACABC4cBAQN/IwBBEGsiAiQAAkAgACgCAEUgACgCBEVzDQAgAiAAKAIINgIIIAIgACkCADcDAAJ/IAIoAgAiAQRAIAIoAghBqOMJIAERBQAMAQtBqOMJECgLIgFFDQAgASAAKQIANwL04QEgAUH84QFqIAAoAgg2AgAgARBZIAEhAwsgAkEQaiQAIAMLywEBAn8jAEEgayIBJAAgAEGBgIDAADYCtOIBIABBADYCiOIBIABBADYC7OEBIABCADcDkOIBIABBADYCpOMJIABBADYC3OIBIABCADcCzOIBIABBADYCvOIBIABBADYCxOABIABCADcCnOIBIABBpOIBakIANwIAIABBrOIBakEANgIAIAFCADcCECABQgA3AhggASABKQMYNwMIIAEgASkDEDcDACABKAIIQQh2QQFxIQIgAEEANgLg4gEgACACNgKM4gEgAUEgaiQAC3YBA38jAEEwayIBJAAgAARAIAEgAEHE0AFqIgIoAgA2AiggASAAKQK80AE3AyAgACgCACEDIAEgAigCADYCGCABIAApArzQATcDECADIAFBEGoQGyABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALzAEBAX8gACABKAK00AE2ApjiASAAIAEoAgQiAjYCwOABIAAgAjYCvOABIAAgAiABKAIIaiICNgK44AEgACACNgLE4AEgASgCuNABBEAgAEKBgICAEDcDiOEBIAAgAUGk0ABqNgIMIAAgAUGUIGo2AgggACABQZwwajYCBCAAIAFBDGo2AgAgAEGs0AFqIAFBqNABaigCADYCACAAQbDQAWogAUGs0AFqKAIANgIAIABBtNABaiABQbDQAWooAgA2AgAPCyAAQgA3A4jhAQs7ACACRQRAQbp/DwsgBEUEQEFsDwsgAiAEEGAEQCAAIAEgAiADIAQgBRBhDwsgACABIAIgAyAEIAUQZQtGAQF/IwBBEGsiBSQAIAVBCGogBBAOAn8gBS0ACQRAIAAgASACIAMgBBAyDAELIAAgASACIAMgBBA0CyEAIAVBEGokACAACzQAIAAgAyAEIAUQNiIFEAMEQCAFDwsgBSAESQR/IAEgAiADIAVqIAQgBWsgABA1BUG4fwsLRgEBfyMAQRBrIgUkACAFQQhqIAQQDgJ/IAUtAAkEQCAAIAEgAiADIAQQYgwBCyAAIAEgAiADIAQQNQshACAFQRBqJAAgAAtZAQF/QQ8hAiABIABJBEAgAUEEdCAAbiECCyAAQQh2IgEgAkEYbCIAQYwIaigCAGwgAEGICGooAgBqIgJBA3YgAmogAEGACGooAgAgAEGECGooAgAgAWxqSQs3ACAAIAMgBCAFQYAQEDMiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQMgVBuH8LC78DAQN/IwBBIGsiBSQAIAVBCGogAiADEAYiAhADRQRAIAAgAWoiB0F9aiEGIAUgBBAOIARBBGohAiAFLQACIQMDQEEAIAAgBkkgBUEIahAEGwRAIAAgAiAFQQhqIAMQAkECdGoiBC8BADsAACAFQQhqIAQtAAIQASAAIAQtAANqIgQgAiAFQQhqIAMQAkECdGoiAC8BADsAACAFQQhqIAAtAAIQASAEIAAtAANqIQAMAQUgB0F+aiEEA0AgBUEIahAEIAAgBEtyRQRAIAAgAiAFQQhqIAMQAkECdGoiBi8BADsAACAFQQhqIAYtAAIQASAAIAYtAANqIQAMAQsLA0AgACAES0UEQCAAIAIgBUEIaiADEAJBAnRqIgYvAQA7AAAgBUEIaiAGLQACEAEgACAGLQADaiEADAELCwJAIAAgB08NACAAIAIgBUEIaiADEAIiA0ECdGoiAC0AADoAACAALQADQQFGBEAgBUEIaiAALQACEAEMAQsgBSgCDEEfSw0AIAVBCGogAiADQQJ0ai0AAhABIAUoAgxBIUkNACAFQSA2AgwLIAFBbCAFQQhqEAobIQILCwsgBUEgaiQAIAILkgIBBH8jAEFAaiIJJAAgCSADQTQQCyEDAkAgBEECSA0AIAMgBEECdGooAgAhCSADQTxqIAgQIyADQQE6AD8gAyACOgA+QQAhBCADKAI8IQoDQCAEIAlGDQEgACAEQQJ0aiAKNgEAIARBAWohBAwAAAsAC0EAIQkDQCAGIAlGRQRAIAMgBSAJQQF0aiIKLQABIgtBAnRqIgwoAgAhBCADQTxqIAotAABBCHQgCGpB//8DcRAjIANBAjoAPyADIAcgC2siCiACajoAPiAEQQEgASAKa3RqIQogAygCPCELA0AgACAEQQJ0aiALNgEAIARBAWoiBCAKSQ0ACyAMIAo2AgAgCUEBaiEJDAELCyADQUBrJAALowIBCX8jAEHQAGsiCSQAIAlBEGogBUE0EAsaIAcgBmshDyAHIAFrIRADQAJAIAMgCkcEQEEBIAEgByACIApBAXRqIgYtAAEiDGsiCGsiC3QhDSAGLQAAIQ4gCUEQaiAMQQJ0aiIMKAIAIQYgCyAPTwRAIAAgBkECdGogCyAIIAUgCEE0bGogCCAQaiIIQQEgCEEBShsiCCACIAQgCEECdGooAgAiCEEBdGogAyAIayAHIA4QYyAGIA1qIQgMAgsgCUEMaiAOECMgCUEBOgAPIAkgCDoADiAGIA1qIQggCSgCDCELA0AgBiAITw0CIAAgBkECdGogCzYBACAGQQFqIQYMAAALAAsgCUHQAGokAA8LIAwgCDYCACAKQQFqIQoMAAALAAs0ACAAIAMgBCAFEDYiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQNAVBuH8LCyMAIAA/AEEQdGtB//8DakEQdkAAQX9GBEBBAA8LQQAQAEEBCzsBAX8gAgRAA0AgACABIAJBgCAgAkGAIEkbIgMQCyEAIAFBgCBqIQEgAEGAIGohACACIANrIgINAAsLCwYAIAAQAwsLqBUJAEGICAsNAQAAAAEAAAACAAAAAgBBoAgLswYBAAAAAQAAAAIAAAACAAAAJgAAAIIAAAAhBQAASgAAAGcIAAAmAAAAwAEAAIAAAABJBQAASgAAAL4IAAApAAAALAIAAIAAAABJBQAASgAAAL4IAAAvAAAAygIAAIAAAACKBQAASgAAAIQJAAA1AAAAcwMAAIAAAACdBQAASgAAAKAJAAA9AAAAgQMAAIAAAADrBQAASwAAAD4KAABEAAAAngMAAIAAAABNBgAASwAAAKoKAABLAAAAswMAAIAAAADBBgAATQAAAB8NAABNAAAAUwQAAIAAAAAjCAAAUQAAAKYPAABUAAAAmQQAAIAAAABLCQAAVwAAALESAABYAAAA2gQAAIAAAABvCQAAXQAAACMUAABUAAAARQUAAIAAAABUCgAAagAAAIwUAABqAAAArwUAAIAAAAB2CQAAfAAAAE4QAAB8AAAA0gIAAIAAAABjBwAAkQAAAJAHAACSAAAAAAAAAAEAAAABAAAABQAAAA0AAAAdAAAAPQAAAH0AAAD9AAAA/QEAAP0DAAD9BwAA/Q8AAP0fAAD9PwAA/X8AAP3/AAD9/wEA/f8DAP3/BwD9/w8A/f8fAP3/PwD9/38A/f//AP3//wH9//8D/f//B/3//w/9//8f/f//P/3//38AAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACUAAAAnAAAAKQAAACsAAAAvAAAAMwAAADsAAABDAAAAUwAAAGMAAACDAAAAAwEAAAMCAAADBAAAAwgAAAMQAAADIAAAA0AAAAOAAAADAAEAQeAPC1EBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAQcQQC4sBAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABIAAAAUAAAAFgAAABgAAAAcAAAAIAAAACgAAAAwAAAAQAAAAIAAAAAAAQAAAAIAAAAEAAAACAAAABAAAAAgAAAAQAAAAIAAAAAAAQBBkBIL5gQBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAAAEAAAAEAAAACAAAAAAAAAABAAEBBgAAAAAAAAQAAAAAEAAABAAAAAAgAAAFAQAAAAAAAAUDAAAAAAAABQQAAAAAAAAFBgAAAAAAAAUHAAAAAAAABQkAAAAAAAAFCgAAAAAAAAUMAAAAAAAABg4AAAAAAAEFEAAAAAAAAQUUAAAAAAABBRYAAAAAAAIFHAAAAAAAAwUgAAAAAAAEBTAAAAAgAAYFQAAAAAAABwWAAAAAAAAIBgABAAAAAAoGAAQAAAAADAYAEAAAIAAABAAAAAAAAAAEAQAAAAAAAAUCAAAAIAAABQQAAAAAAAAFBQAAACAAAAUHAAAAAAAABQgAAAAgAAAFCgAAAAAAAAULAAAAAAAABg0AAAAgAAEFEAAAAAAAAQUSAAAAIAABBRYAAAAAAAIFGAAAACAAAwUgAAAAAAADBSgAAAAAAAYEQAAAABAABgRAAAAAIAAHBYAAAAAAAAkGAAIAAAAACwYACAAAMAAABAAAAAAQAAAEAQAAACAAAAUCAAAAIAAABQMAAAAgAAAFBQAAACAAAAUGAAAAIAAABQgAAAAgAAAFCQAAACAAAAULAAAAIAAABQwAAAAAAAAGDwAAACAAAQUSAAAAIAABBRQAAAAgAAIFGAAAACAAAgUcAAAAIAADBSgAAAAgAAQFMAAAAAAAEAYAAAEAAAAPBgCAAAAAAA4GAEAAAAAADQYAIABBgBcLhwIBAAEBBQAAAAAAAAUAAAAAAAAGBD0AAAAAAAkF/QEAAAAADwX9fwAAAAAVBf3/HwAAAAMFBQAAAAAABwR9AAAAAAAMBf0PAAAAABIF/f8DAAAAFwX9/38AAAAFBR0AAAAAAAgE/QAAAAAADgX9PwAAAAAUBf3/DwAAAAIFAQAAABAABwR9AAAAAAALBf0HAAAAABEF/f8BAAAAFgX9/z8AAAAEBQ0AAAAQAAgE/QAAAAAADQX9HwAAAAATBf3/BwAAAAEFAQAAABAABgQ9AAAAAAAKBf0DAAAAABAF/f8AAAAAHAX9//8PAAAbBf3//wcAABoF/f//AwAAGQX9//8BAAAYBf3//wBBkBkLhgQBAAEBBgAAAAAAAAYDAAAAAAAABAQAAAAgAAAFBQAAAAAAAAUGAAAAAAAABQgAAAAAAAAFCQAAAAAAAAULAAAAAAAABg0AAAAAAAAGEAAAAAAAAAYTAAAAAAAABhYAAAAAAAAGGQAAAAAAAAYcAAAAAAAABh8AAAAAAAAGIgAAAAAAAQYlAAAAAAABBikAAAAAAAIGLwAAAAAAAwY7AAAAAAAEBlMAAAAAAAcGgwAAAAAACQYDAgAAEAAABAQAAAAAAAAEBQAAACAAAAUGAAAAAAAABQcAAAAgAAAFCQAAAAAAAAUKAAAAAAAABgwAAAAAAAAGDwAAAAAAAAYSAAAAAAAABhUAAAAAAAAGGAAAAAAAAAYbAAAAAAAABh4AAAAAAAAGIQAAAAAAAQYjAAAAAAABBicAAAAAAAIGKwAAAAAAAwYzAAAAAAAEBkMAAAAAAAUGYwAAAAAACAYDAQAAIAAABAQAAAAwAAAEBAAAABAAAAQFAAAAIAAABQcAAAAgAAAFCAAAACAAAAUKAAAAIAAABQsAAAAAAAAGDgAAAAAAAAYRAAAAAAAABhQAAAAAAAAGFwAAAAAAAAYaAAAAAAAABh0AAAAAAAAGIAAAAAAAEAYDAAEAAAAPBgOAAAAAAA4GA0AAAAAADQYDIAAAAAAMBgMQAAAAAAsGAwgAAAAACgYDBABBpB0L2QEBAAAAAwAAAAcAAAAPAAAAHwAAAD8AAAB/AAAA/wAAAP8BAAD/AwAA/wcAAP8PAAD/HwAA/z8AAP9/AAD//wAA//8BAP//AwD//wcA//8PAP//HwD//z8A//9/AP///wD///8B////A////wf///8P////H////z////9/AAAAAAEAAAACAAAABAAAAAAAAAACAAAABAAAAAgAAAAAAAAAAQAAAAIAAAABAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAcAAAAIAAAACQAAAAoAAAALAEGgIAsDwBBQ"; //#endregion //#region node_modules/three-stdlib/_polyfill/CompressedCubeTexture.js var CompressedCubeTexture = class extends CompressedTexture { constructor(images, format, type) { super(void 0, images[0].width, images[0].height, format, type, 301); this.isCompressedCubeTexture = true; this.isCubeTexture = true; this.image = images; } }; //#endregion //#region node_modules/three-stdlib/_polyfill/CompressedArrayTexture.js var CompressedArrayTexture = class extends CompressedTexture { constructor(mipmaps, width, height, depth, format, type) { super(mipmaps, width, height, format, type); this.isCompressedArrayTexture = true; this.image.depth = depth; this.wrapR = ClampToEdgeWrapping; } }; //#endregion //#region node_modules/three-stdlib/loaders/KTX2Loader.js var __defProp$1 = Object.defineProperty; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => { __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var LinearEncoding = 3e3; var sRGBEncoding = 3001; var NoColorSpace = ""; var DisplayP3ColorSpace = "display-p3"; var LinearDisplayP3ColorSpace = "display-p3-linear"; var LinearSRGBColorSpace = "srgb-linear"; var SRGBColorSpace = "srgb"; var _taskCache$1 = /* @__PURE__ */ new WeakMap(); var _activeLoaders = 0; var _zstd; var KTX2Loader = /* @__PURE__ */ (() => { const _KTX2Loader = class extends Loader$1 { constructor(manager) { super(manager); this.transcoderPath = ""; this.transcoderBinary = null; this.transcoderPending = null; this.workerPool = new WorkerPool(); this.workerSourceURL = ""; this.workerConfig = null; if (typeof MSC_TRANSCODER !== "undefined") console.warn("THREE.KTX2Loader: Please update to latest \"basis_transcoder\". \"msc_basis_transcoder\" is no longer supported in three.js r125+."); } setTranscoderPath(path) { this.transcoderPath = path; return this; } setWorkerLimit(num) { this.workerPool.setWorkerLimit(num); return this; } detectSupport(renderer) { this.workerConfig = { astcSupported: renderer.extensions.has("WEBGL_compressed_texture_astc"), etc1Supported: renderer.extensions.has("WEBGL_compressed_texture_etc1"), etc2Supported: renderer.extensions.has("WEBGL_compressed_texture_etc"), dxtSupported: renderer.extensions.has("WEBGL_compressed_texture_s3tc"), bptcSupported: renderer.extensions.has("EXT_texture_compression_bptc"), pvrtcSupported: renderer.extensions.has("WEBGL_compressed_texture_pvrtc") || renderer.extensions.has("WEBKIT_WEBGL_compressed_texture_pvrtc") }; if (renderer.capabilities.isWebGL2) this.workerConfig.etc1Supported = false; return this; } init() { if (!this.transcoderPending) { const jsLoader = new FileLoader(this.manager); jsLoader.setPath(this.transcoderPath); jsLoader.setWithCredentials(this.withCredentials); const jsContent = jsLoader.loadAsync("basis_transcoder.js"); const binaryLoader = new FileLoader(this.manager); binaryLoader.setPath(this.transcoderPath); binaryLoader.setResponseType("arraybuffer"); binaryLoader.setWithCredentials(this.withCredentials); const binaryContent = binaryLoader.loadAsync("basis_transcoder.wasm"); this.transcoderPending = Promise.all([jsContent, binaryContent]).then(([jsContent2, binaryContent2]) => { const fn = _KTX2Loader.BasisWorker.toString(); const body = [ "/* constants */", "let _EngineFormat = " + JSON.stringify(_KTX2Loader.EngineFormat), "let _TranscoderFormat = " + JSON.stringify(_KTX2Loader.TranscoderFormat), "let _BasisFormat = " + JSON.stringify(_KTX2Loader.BasisFormat), "/* basis_transcoder.js */", jsContent2, "/* worker */", fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")) ].join("\n"); this.workerSourceURL = URL.createObjectURL(new Blob([body])); this.transcoderBinary = binaryContent2; this.workerPool.setWorkerCreator(() => { const worker = new Worker(this.workerSourceURL); const transcoderBinary = this.transcoderBinary.slice(0); worker.postMessage({ type: "init", config: this.workerConfig, transcoderBinary }, [transcoderBinary]); return worker; }); }); if (_activeLoaders > 0) console.warn("THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues. Use a single KTX2Loader instance, or call .dispose() on old instances."); _activeLoaders++; } return this.transcoderPending; } load(url, onLoad, onProgress, onError) { if (this.workerConfig === null) throw new Error("THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`."); const loader = new FileLoader(this.manager); loader.setResponseType("arraybuffer"); loader.setWithCredentials(this.withCredentials); loader.load(url, (buffer) => { if (_taskCache$1.has(buffer)) return _taskCache$1.get(buffer).promise.then(onLoad).catch(onError); this._createTexture(buffer).then((texture) => onLoad ? onLoad(texture) : null).catch(onError); }, onProgress, onError); } _createTextureFrom(transcodeResult, container) { const { faces, width, height, format, type, error, dfdFlags } = transcodeResult; if (type === "error") return Promise.reject(error); let texture; if (container.faceCount === 6) texture = new CompressedCubeTexture(faces, format, UnsignedByteType); else { const mipmaps = faces[0].mipmaps; texture = container.layerCount > 1 ? new CompressedArrayTexture(mipmaps, width, height, container.layerCount, format, UnsignedByteType) : new CompressedTexture(mipmaps, width, height, format, UnsignedByteType); } texture.minFilter = faces[0].mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter; texture.magFilter = LinearFilter; texture.generateMipmaps = false; texture.needsUpdate = true; const colorSpace = parseColorSpace(container); if ("colorSpace" in texture) texture.colorSpace = colorSpace; else texture.encoding = colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; texture.premultiplyAlpha = !!(dfdFlags & 1); return texture; } /** * @param {ArrayBuffer} buffer * @param {object?} config * @return {Promise} */ async _createTexture(buffer, config = {}) { const container = read(new Uint8Array(buffer)); if (container.vkFormat !== 0) return createRawTexture(container); const taskConfig = config; const texturePending = this.init().then(() => { return this.workerPool.postMessage({ type: "transcode", buffer, taskConfig }, [buffer]); }).then((e) => this._createTextureFrom(e.data, container)); _taskCache$1.set(buffer, { promise: texturePending }); return texturePending; } dispose() { this.workerPool.dispose(); if (this.workerSourceURL) URL.revokeObjectURL(this.workerSourceURL); _activeLoaders--; return this; } }; let KTX2Loader2 = _KTX2Loader; __publicField$1(KTX2Loader2, "BasisFormat", { ETC1S: 0, UASTC_4x4: 1 }); __publicField$1(KTX2Loader2, "TranscoderFormat", { ETC1: 0, ETC2: 1, BC1: 2, BC3: 3, BC4: 4, BC5: 5, BC7_M6_OPAQUE_ONLY: 6, BC7_M5: 7, PVRTC1_4_RGB: 8, PVRTC1_4_RGBA: 9, ASTC_4x4: 10, ATC_RGB: 11, ATC_RGBA_INTERPOLATED_ALPHA: 12, RGBA32: 13, RGB565: 14, BGR565: 15, RGBA4444: 16 }); __publicField$1(KTX2Loader2, "EngineFormat", { RGBAFormat, RGBA_ASTC_4x4_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format }); __publicField$1(KTX2Loader2, "BasisWorker", function() { let config; let transcoderPending; let BasisModule; const EngineFormat = _EngineFormat; const TranscoderFormat = _TranscoderFormat; const BasisFormat = _BasisFormat; self.addEventListener("message", function(e) { const message = e.data; switch (message.type) { case "init": config = message.config; init(message.transcoderBinary); break; case "transcode": transcoderPending.then(() => { try { const { faces, buffers, width, height, hasAlpha, format, dfdFlags } = transcode(message.buffer); self.postMessage({ type: "transcode", id: message.id, faces, width, height, hasAlpha, format, dfdFlags }, buffers); } catch (error) { console.error(error); self.postMessage({ type: "error", id: message.id, error: error.message }); } }); break; } }); function init(wasmBinary) { transcoderPending = new Promise((resolve) => { BasisModule = { wasmBinary, onRuntimeInitialized: resolve }; BASIS(BasisModule); }).then(() => { BasisModule.initializeBasis(); if (BasisModule.KTX2File === void 0) console.warn("THREE.KTX2Loader: Please update Basis Universal transcoder."); }); } function transcode(buffer) { const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)); function cleanup() { ktx2File.close(); ktx2File.delete(); } if (!ktx2File.isValid()) { cleanup(); throw new Error("THREE.KTX2Loader: Invalid or unsupported .ktx2 file"); } const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S; const width = ktx2File.getWidth(); const height = ktx2File.getHeight(); const layerCount = ktx2File.getLayers() || 1; const levelCount = ktx2File.getLevels(); const faceCount = ktx2File.getFaces(); const hasAlpha = ktx2File.getHasAlpha(); const dfdFlags = ktx2File.getDFDFlags(); const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha); if (!width || !height || !levelCount) { cleanup(); throw new Error("THREE.KTX2Loader: Invalid texture"); } if (!ktx2File.startTranscoding()) { cleanup(); throw new Error("THREE.KTX2Loader: .startTranscoding failed"); } const faces = []; const buffers = []; for (let face = 0; face < faceCount; face++) { const mipmaps = []; for (let mip = 0; mip < levelCount; mip++) { const layerMips = []; let mipWidth, mipHeight; for (let layer = 0; layer < layerCount; layer++) { const levelInfo = ktx2File.getImageLevelInfo(mip, layer, face); if (face === 0 && mip === 0 && layer === 0 && (levelInfo.origWidth % 4 !== 0 || levelInfo.origHeight % 4 !== 0)) console.warn("THREE.KTX2Loader: ETC1S and UASTC textures should use multiple-of-four dimensions."); if (levelCount > 1) { mipWidth = levelInfo.origWidth; mipHeight = levelInfo.origHeight; } else { mipWidth = levelInfo.width; mipHeight = levelInfo.height; } const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, layer, 0, transcoderFormat)); if (!ktx2File.transcodeImage(dst, mip, layer, face, transcoderFormat, 0, -1, -1)) { cleanup(); throw new Error("THREE.KTX2Loader: .transcodeImage failed."); } layerMips.push(dst); } const mipData = concat(layerMips); mipmaps.push({ data: mipData, width: mipWidth, height: mipHeight }); buffers.push(mipData.buffer); } faces.push({ mipmaps, width, height, format: engineFormat }); } cleanup(); return { faces, buffers, width, height, hasAlpha, format: engineFormat, dfdFlags }; } const FORMAT_OPTIONS = [ { if: "astcSupported", basisFormat: [BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], priorityETC1S: Infinity, priorityUASTC: 1, needsPowerOfTwo: false }, { if: "bptcSupported", basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], priorityETC1S: 3, priorityUASTC: 2, needsPowerOfTwo: false }, { if: "dxtSupported", basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], priorityETC1S: 4, priorityUASTC: 5, needsPowerOfTwo: false }, { if: "etc2Supported", basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], priorityETC1S: 1, priorityUASTC: 3, needsPowerOfTwo: false }, { if: "etc1Supported", basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.ETC1], engineFormat: [EngineFormat.RGB_ETC1_Format], priorityETC1S: 2, priorityUASTC: 4, needsPowerOfTwo: false }, { if: "pvrtcSupported", basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], priorityETC1S: 5, priorityUASTC: 6, needsPowerOfTwo: true } ]; const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function(a, b) { return a.priorityETC1S - b.priorityETC1S; }); const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function(a, b) { return a.priorityUASTC - b.priorityUASTC; }); function getTranscoderFormat(basisFormat, width, height, hasAlpha) { let transcoderFormat; let engineFormat; const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS; for (let i = 0; i < options.length; i++) { const opt = options[i]; if (!config[opt.if]) continue; if (!opt.basisFormat.includes(basisFormat)) continue; if (hasAlpha && opt.transcoderFormat.length < 2) continue; if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue; transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0]; engineFormat = opt.engineFormat[hasAlpha ? 1 : 0]; return { transcoderFormat, engineFormat }; } console.warn("THREE.KTX2Loader: No suitable compressed texture format found. Decoding to RGBA32."); transcoderFormat = TranscoderFormat.RGBA32; engineFormat = EngineFormat.RGBAFormat; return { transcoderFormat, engineFormat }; } function isPowerOfTwo(value) { if (value <= 2) return true; return (value & value - 1) === 0 && value !== 0; } function concat(arrays) { if (arrays.length === 1) return arrays[0]; let totalByteLength = 0; for (let i = 0; i < arrays.length; i++) { const array = arrays[i]; totalByteLength += array.byteLength; } const result = new Uint8Array(totalByteLength); let byteOffset = 0; for (let i = 0; i < arrays.length; i++) { const array = arrays[i]; result.set(array, byteOffset); byteOffset += array.byteLength; } return result; } }); return KTX2Loader2; })(); var UNCOMPRESSED_FORMATS = /* @__PURE__ */ new Set([ RGBAFormat, RGFormat, RedFormat ]); var FORMAT_MAP = { [109]: RGBAFormat, [97]: RGBAFormat, [37]: RGBAFormat, [43]: RGBAFormat, [103]: RGFormat, [83]: RGFormat, [16]: RGFormat, [22]: RGFormat, [100]: RedFormat, [76]: RedFormat, [15]: RedFormat, [9]: RedFormat, [166]: RGBA_ASTC_6x6_Format, [165]: RGBA_ASTC_6x6_Format }; var TYPE_MAP = { [109]: FloatType, [97]: HalfFloatType, [37]: UnsignedByteType, [43]: UnsignedByteType, [103]: FloatType, [83]: HalfFloatType, [16]: UnsignedByteType, [22]: UnsignedByteType, [100]: FloatType, [76]: HalfFloatType, [15]: UnsignedByteType, [9]: UnsignedByteType, [166]: UnsignedByteType, [165]: UnsignedByteType }; async function createRawTexture(container) { const { vkFormat } = container; if (FORMAT_MAP[vkFormat] === void 0) throw new Error("THREE.KTX2Loader: Unsupported vkFormat."); let zstd; if (container.supercompressionScheme === 2) { if (!_zstd) _zstd = new Promise(async (resolve) => { const zstd2 = new ZSTDDecoder(); await zstd2.init(); resolve(zstd2); }); zstd = await _zstd; } const mipmaps = []; for (let levelIndex = 0; levelIndex < container.levels.length; levelIndex++) { const levelWidth = Math.max(1, container.pixelWidth >> levelIndex); const levelHeight = Math.max(1, container.pixelHeight >> levelIndex); const levelDepth = container.pixelDepth ? Math.max(1, container.pixelDepth >> levelIndex) : 0; const level = container.levels[levelIndex]; let levelData; if (container.supercompressionScheme === 0) levelData = level.levelData; else if (container.supercompressionScheme === 2) levelData = zstd.decode(level.levelData, level.uncompressedByteLength); else throw new Error("THREE.KTX2Loader: Unsupported supercompressionScheme."); let data; if (TYPE_MAP[vkFormat] === 1015) data = new Float32Array(levelData.buffer, levelData.byteOffset, levelData.byteLength / Float32Array.BYTES_PER_ELEMENT); else if (TYPE_MAP[vkFormat] === 1016) data = new Uint16Array(levelData.buffer, levelData.byteOffset, levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT); else data = levelData; mipmaps.push({ data, width: levelWidth, height: levelHeight, depth: levelDepth }); } let texture; if (UNCOMPRESSED_FORMATS.has(FORMAT_MAP[vkFormat])) texture = container.pixelDepth === 0 ? new DataTexture(mipmaps[0].data, container.pixelWidth, container.pixelHeight) : new Data3DTexture(mipmaps[0].data, container.pixelWidth, container.pixelHeight, container.pixelDepth); else { if (container.pixelDepth > 0) throw new Error("THREE.KTX2Loader: Unsupported pixelDepth."); texture = new CompressedTexture(mipmaps, container.pixelWidth, container.pixelHeight); } texture.mipmaps = mipmaps; texture.type = TYPE_MAP[vkFormat]; texture.format = FORMAT_MAP[vkFormat]; texture.needsUpdate = true; const colorSpace = parseColorSpace(container); if ("colorSpace" in texture) texture.colorSpace = colorSpace; else texture.encoding = colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; return Promise.resolve(texture); } function parseColorSpace(container) { const dfd = container.dataFormatDescriptor[0]; if (dfd.colorPrimaries === 1) return dfd.transferFunction === 2 ? SRGBColorSpace : LinearSRGBColorSpace; else if (dfd.colorPrimaries === 10) return dfd.transferFunction === 2 ? DisplayP3ColorSpace : LinearDisplayP3ColorSpace; else if (dfd.colorPrimaries === 0) return NoColorSpace; else { console.warn(`THREE.KTX2Loader: Unsupported color primaries, "${dfd.colorPrimaries}"`); return NoColorSpace; } } //#endregion //#region node_modules/three-stdlib/loaders/RGBELoader.js var RGBELoader = class extends DataTextureLoader { constructor(manager) { super(manager); this.type = HalfFloatType; } parse(buffer) { const rgbe_read_error = 1, rgbe_write_error = 2, rgbe_format_error = 3, rgbe_memory_error = 4, rgbe_error = function(rgbe_error_code, msg) { switch (rgbe_error_code) { case rgbe_read_error: throw new Error("THREE.RGBELoader: Read Error: " + (msg || "")); case rgbe_write_error: throw new Error("THREE.RGBELoader: Write Error: " + (msg || "")); case rgbe_format_error: throw new Error("THREE.RGBELoader: Bad File Format: " + (msg || "")); default: case rgbe_memory_error: throw new Error("THREE.RGBELoader: Memory Error: " + (msg || "")); } }, RGBE_VALID_PROGRAMTYPE = 1, RGBE_VALID_FORMAT = 2, RGBE_VALID_DIMENSIONS = 4, NEWLINE = "\n", fgets = function(buffer2, lineLimit, consume) { const chunkSize = 128; lineLimit = !lineLimit ? 1024 : lineLimit; let p = buffer2.pos, i = -1, len = 0, s = "", chunk = String.fromCharCode.apply(null, new Uint16Array(buffer2.subarray(p, p + chunkSize))); while (0 > (i = chunk.indexOf(NEWLINE)) && len < lineLimit && p < buffer2.byteLength) { s += chunk; len += chunk.length; p += chunkSize; chunk += String.fromCharCode.apply(null, new Uint16Array(buffer2.subarray(p, p + chunkSize))); } if (-1 < i) { if (false !== consume) buffer2.pos += len + i + 1; return s + chunk.slice(0, i); } return false; }, RGBE_ReadHeader = function(buffer2) { const magic_token_re = /^#\?(\S+)/, gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, format_re = /^\s*FORMAT=(\S+)\s*$/, dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, header = { valid: 0, string: "", comments: "", programtype: "RGBE", format: "", gamma: 1, exposure: 1, width: 0, height: 0 }; let line, match; if (buffer2.pos >= buffer2.byteLength || !(line = fgets(buffer2))) rgbe_error(rgbe_read_error, "no header found"); if (!(match = line.match(magic_token_re))) rgbe_error(rgbe_format_error, "bad initial token"); header.valid |= RGBE_VALID_PROGRAMTYPE; header.programtype = match[1]; header.string += line + "\n"; while (true) { line = fgets(buffer2); if (false === line) break; header.string += line + "\n"; if ("#" === line.charAt(0)) { header.comments += line + "\n"; continue; } if (match = line.match(gamma_re)) header.gamma = parseFloat(match[1]); if (match = line.match(exposure_re)) header.exposure = parseFloat(match[1]); if (match = line.match(format_re)) { header.valid |= RGBE_VALID_FORMAT; header.format = match[1]; } if (match = line.match(dimensions_re)) { header.valid |= RGBE_VALID_DIMENSIONS; header.height = parseInt(match[1], 10); header.width = parseInt(match[2], 10); } if (header.valid & RGBE_VALID_FORMAT && header.valid & RGBE_VALID_DIMENSIONS) break; } if (!(header.valid & RGBE_VALID_FORMAT)) rgbe_error(rgbe_format_error, "missing format specifier"); if (!(header.valid & RGBE_VALID_DIMENSIONS)) rgbe_error(rgbe_format_error, "missing image size specifier"); return header; }, RGBE_ReadPixels_RLE = function(buffer2, w2, h2) { const scanline_width = w2; if (scanline_width < 8 || scanline_width > 32767 || 2 !== buffer2[0] || 2 !== buffer2[1] || buffer2[2] & 128) return new Uint8Array(buffer2); if (scanline_width !== (buffer2[2] << 8 | buffer2[3])) rgbe_error(rgbe_format_error, "wrong scanline width"); const data_rgba = new Uint8Array(4 * w2 * h2); if (!data_rgba.length) rgbe_error(rgbe_memory_error, "unable to allocate buffer space"); let offset = 0, pos = 0; const ptr_end = 4 * scanline_width; const rgbeStart = new Uint8Array(4); const scanline_buffer = new Uint8Array(ptr_end); let num_scanlines = h2; while (num_scanlines > 0 && pos < buffer2.byteLength) { if (pos + 4 > buffer2.byteLength) rgbe_error(rgbe_read_error); rgbeStart[0] = buffer2[pos++]; rgbeStart[1] = buffer2[pos++]; rgbeStart[2] = buffer2[pos++]; rgbeStart[3] = buffer2[pos++]; if (2 != rgbeStart[0] || 2 != rgbeStart[1] || (rgbeStart[2] << 8 | rgbeStart[3]) != scanline_width) rgbe_error(rgbe_format_error, "bad rgbe scanline format"); let ptr = 0, count; while (ptr < ptr_end && pos < buffer2.byteLength) { count = buffer2[pos++]; const isEncodedRun = count > 128; if (isEncodedRun) count -= 128; if (0 === count || ptr + count > ptr_end) rgbe_error(rgbe_format_error, "bad scanline data"); if (isEncodedRun) { const byteValue = buffer2[pos++]; for (let i = 0; i < count; i++) scanline_buffer[ptr++] = byteValue; } else { scanline_buffer.set(buffer2.subarray(pos, pos + count), ptr); ptr += count; pos += count; } } const l = scanline_width; for (let i = 0; i < l; i++) { let off = 0; data_rgba[offset] = scanline_buffer[i + off]; off += scanline_width; data_rgba[offset + 1] = scanline_buffer[i + off]; off += scanline_width; data_rgba[offset + 2] = scanline_buffer[i + off]; off += scanline_width; data_rgba[offset + 3] = scanline_buffer[i + off]; offset += 4; } num_scanlines--; } return data_rgba; }; const RGBEByteToRGBFloat = function(sourceArray, sourceOffset, destArray, destOffset) { const e = sourceArray[sourceOffset + 3]; const scale = Math.pow(2, e - 128) / 255; destArray[destOffset + 0] = sourceArray[sourceOffset + 0] * scale; destArray[destOffset + 1] = sourceArray[sourceOffset + 1] * scale; destArray[destOffset + 2] = sourceArray[sourceOffset + 2] * scale; destArray[destOffset + 3] = 1; }; const RGBEByteToRGBHalf = function(sourceArray, sourceOffset, destArray, destOffset) { const e = sourceArray[sourceOffset + 3]; const scale = Math.pow(2, e - 128) / 255; destArray[destOffset + 0] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 0] * scale, 65504)); destArray[destOffset + 1] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 1] * scale, 65504)); destArray[destOffset + 2] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 2] * scale, 65504)); destArray[destOffset + 3] = DataUtils.toHalfFloat(1); }; const byteArray = new Uint8Array(buffer); byteArray.pos = 0; const rgbe_header_info = RGBE_ReadHeader(byteArray); const w = rgbe_header_info.width, h = rgbe_header_info.height, image_rgba_data = RGBE_ReadPixels_RLE(byteArray.subarray(byteArray.pos), w, h); let data, type; let numElements; switch (this.type) { case FloatType: numElements = image_rgba_data.length / 4; const floatArray = new Float32Array(numElements * 4); for (let j = 0; j < numElements; j++) RGBEByteToRGBFloat(image_rgba_data, j * 4, floatArray, j * 4); data = floatArray; type = FloatType; break; case HalfFloatType: numElements = image_rgba_data.length / 4; const halfArray = new Uint16Array(numElements * 4); for (let j = 0; j < numElements; j++) RGBEByteToRGBHalf(image_rgba_data, j * 4, halfArray, j * 4); data = halfArray; type = HalfFloatType; break; default: throw new Error("THREE.RGBELoader: Unsupported type: " + this.type); } return { width: w, height: h, data, header: rgbe_header_info.string, gamma: rgbe_header_info.gamma, exposure: rgbe_header_info.exposure, type }; } setDataType(value) { this.type = value; return this; } load(url, onLoad, onProgress, onError) { function onLoadCallback(texture, texData) { switch (texture.type) { case FloatType: case HalfFloatType: if ("colorSpace" in texture) texture.colorSpace = "srgb-linear"; else texture.encoding = 3e3; texture.minFilter = LinearFilter; texture.magFilter = LinearFilter; texture.generateMipmaps = false; texture.flipY = true; break; } if (onLoad) onLoad(texture, texData); } return super.load(url, onLoadCallback, onProgress, onError); } }; //#endregion //#region node_modules/three-stdlib/loaders/EXRLoader.js var hasColorSpace = version$2 >= 152; var EXRLoader = class extends DataTextureLoader { constructor(manager) { super(manager); this.type = HalfFloatType; } parse(buffer) { const USHORT_RANGE = 65536; const BITMAP_SIZE = 8192; const HUF_DECBITS = 14; const HUF_ENCSIZE = 65537; const HUF_DECSIZE = 1 << HUF_DECBITS; const HUF_DECMASK = HUF_DECSIZE - 1; const NBITS = 16; const A_OFFSET = 1 << NBITS - 1; const MOD_MASK = (1 << NBITS) - 1; const SHORT_ZEROCODE_RUN = 59; const LONG_ZEROCODE_RUN = 63; const SHORTEST_LONG_RUN = 65 - SHORT_ZEROCODE_RUN; const ULONG_SIZE = 8; const FLOAT32_SIZE = 4; const INT32_SIZE = 4; const INT16_SIZE = 2; const INT8_SIZE = 1; const STATIC_HUFFMAN = 0; const DEFLATE = 1; const UNKNOWN = 0; const LOSSY_DCT = 1; const RLE = 2; const logBase = Math.pow(2.7182818, 2.2); function reverseLutFromBitmap(bitmap, lut) { var k = 0; for (var i = 0; i < USHORT_RANGE; ++i) if (i == 0 || bitmap[i >> 3] & 1 << (i & 7)) lut[k++] = i; var n = k - 1; while (k < USHORT_RANGE) lut[k++] = 0; return n; } function hufClearDecTable(hdec) { for (var i = 0; i < HUF_DECSIZE; i++) { hdec[i] = {}; hdec[i].len = 0; hdec[i].lit = 0; hdec[i].p = null; } } const getBitsReturn = { l: 0, c: 0, lc: 0 }; function getBits(nBits, c, lc, uInt8Array2, inOffset) { while (lc < nBits) { c = c << 8 | parseUint8Array(uInt8Array2, inOffset); lc += 8; } lc -= nBits; getBitsReturn.l = c >> lc & (1 << nBits) - 1; getBitsReturn.c = c; getBitsReturn.lc = lc; } const hufTableBuffer = new Array(59); function hufCanonicalCodeTable(hcode) { for (var i = 0; i <= 58; ++i) hufTableBuffer[i] = 0; for (var i = 0; i < HUF_ENCSIZE; ++i) hufTableBuffer[hcode[i]] += 1; var c = 0; for (var i = 58; i > 0; --i) { var nc = c + hufTableBuffer[i] >> 1; hufTableBuffer[i] = c; c = nc; } for (var i = 0; i < HUF_ENCSIZE; ++i) { var l = hcode[i]; if (l > 0) hcode[i] = l | hufTableBuffer[l]++ << 6; } } function hufUnpackEncTable(uInt8Array2, inDataView, inOffset, ni, im, iM, hcode) { var p = inOffset; var c = 0; var lc = 0; for (; im <= iM; im++) { if (p.value - inOffset.value > ni) return false; getBits(6, c, lc, uInt8Array2, p); var l = getBitsReturn.l; c = getBitsReturn.c; lc = getBitsReturn.lc; hcode[im] = l; if (l == LONG_ZEROCODE_RUN) { if (p.value - inOffset.value > ni) throw "Something wrong with hufUnpackEncTable"; getBits(8, c, lc, uInt8Array2, p); var zerun = getBitsReturn.l + SHORTEST_LONG_RUN; c = getBitsReturn.c; lc = getBitsReturn.lc; if (im + zerun > iM + 1) throw "Something wrong with hufUnpackEncTable"; while (zerun--) hcode[im++] = 0; im--; } else if (l >= SHORT_ZEROCODE_RUN) { var zerun = l - SHORT_ZEROCODE_RUN + 2; if (im + zerun > iM + 1) throw "Something wrong with hufUnpackEncTable"; while (zerun--) hcode[im++] = 0; im--; } } hufCanonicalCodeTable(hcode); } function hufLength(code) { return code & 63; } function hufCode(code) { return code >> 6; } function hufBuildDecTable(hcode, im, iM, hdecod) { for (; im <= iM; im++) { var c = hufCode(hcode[im]); var l = hufLength(hcode[im]); if (c >> l) throw "Invalid table entry"; if (l > HUF_DECBITS) { var pl = hdecod[c >> l - HUF_DECBITS]; if (pl.len) throw "Invalid table entry"; pl.lit++; if (pl.p) { var p = pl.p; pl.p = new Array(pl.lit); for (var i = 0; i < pl.lit - 1; ++i) pl.p[i] = p[i]; } else pl.p = new Array(1); pl.p[pl.lit - 1] = im; } else if (l) { var plOffset = 0; for (var i = 1 << HUF_DECBITS - l; i > 0; i--) { var pl = hdecod[(c << HUF_DECBITS - l) + plOffset]; if (pl.len || pl.p) throw "Invalid table entry"; pl.len = l; pl.lit = im; plOffset++; } } } return true; } const getCharReturn = { c: 0, lc: 0 }; function getChar(c, lc, uInt8Array2, inOffset) { c = c << 8 | parseUint8Array(uInt8Array2, inOffset); lc += 8; getCharReturn.c = c; getCharReturn.lc = lc; } const getCodeReturn = { c: 0, lc: 0 }; function getCode(po, rlc, c, lc, uInt8Array2, inDataView, inOffset, outBuffer, outBufferOffset, outBufferEndOffset) { if (po == rlc) { if (lc < 8) { getChar(c, lc, uInt8Array2, inOffset); c = getCharReturn.c; lc = getCharReturn.lc; } lc -= 8; var cs = c >> lc; var cs = new Uint8Array([cs])[0]; if (outBufferOffset.value + cs > outBufferEndOffset) return false; var s = outBuffer[outBufferOffset.value - 1]; while (cs-- > 0) outBuffer[outBufferOffset.value++] = s; } else if (outBufferOffset.value < outBufferEndOffset) outBuffer[outBufferOffset.value++] = po; else return false; getCodeReturn.c = c; getCodeReturn.lc = lc; } function UInt16(value) { return value & 65535; } function Int16(value) { var ref = UInt16(value); return ref > 32767 ? ref - 65536 : ref; } const wdec14Return = { a: 0, b: 0 }; function wdec14(l, h) { var ls = Int16(l); var hi = Int16(h); var ai = ls + (hi & 1) + (hi >> 1); var as = ai; var bs = ai - hi; wdec14Return.a = as; wdec14Return.b = bs; } function wdec16(l, h) { var m = UInt16(l); var d = UInt16(h); var bb = m - (d >> 1) & MOD_MASK; wdec14Return.a = d + bb - A_OFFSET & MOD_MASK; wdec14Return.b = bb; } function wav2Decode(buffer2, j, nx, ox, ny, oy, mx) { var w14 = mx < 16384; var n = nx > ny ? ny : nx; var p = 1; var p2; while (p <= n) p <<= 1; p >>= 1; p2 = p; p >>= 1; while (p >= 1) { var py = 0; var ey = py + oy * (ny - p2); var oy1 = oy * p; var oy2 = oy * p2; var ox1 = ox * p; var ox2 = ox * p2; var i00, i01, i10, i11; for (; py <= ey; py += oy2) { var px = py; var ex = py + ox * (nx - p2); for (; px <= ex; px += ox2) { var p01 = px + ox1; var p10 = px + oy1; var p11 = p10 + ox1; if (w14) { wdec14(buffer2[px + j], buffer2[p10 + j]); i00 = wdec14Return.a; i10 = wdec14Return.b; wdec14(buffer2[p01 + j], buffer2[p11 + j]); i01 = wdec14Return.a; i11 = wdec14Return.b; wdec14(i00, i01); buffer2[px + j] = wdec14Return.a; buffer2[p01 + j] = wdec14Return.b; wdec14(i10, i11); buffer2[p10 + j] = wdec14Return.a; buffer2[p11 + j] = wdec14Return.b; } else { wdec16(buffer2[px + j], buffer2[p10 + j]); i00 = wdec14Return.a; i10 = wdec14Return.b; wdec16(buffer2[p01 + j], buffer2[p11 + j]); i01 = wdec14Return.a; i11 = wdec14Return.b; wdec16(i00, i01); buffer2[px + j] = wdec14Return.a; buffer2[p01 + j] = wdec14Return.b; wdec16(i10, i11); buffer2[p10 + j] = wdec14Return.a; buffer2[p11 + j] = wdec14Return.b; } } if (nx & p) { var p10 = px + oy1; if (w14) wdec14(buffer2[px + j], buffer2[p10 + j]); else wdec16(buffer2[px + j], buffer2[p10 + j]); i00 = wdec14Return.a; buffer2[p10 + j] = wdec14Return.b; buffer2[px + j] = i00; } } if (ny & p) { var px = py; var ex = py + ox * (nx - p2); for (; px <= ex; px += ox2) { var p01 = px + ox1; if (w14) wdec14(buffer2[px + j], buffer2[p01 + j]); else wdec16(buffer2[px + j], buffer2[p01 + j]); i00 = wdec14Return.a; buffer2[p01 + j] = wdec14Return.b; buffer2[px + j] = i00; } } p2 = p; p >>= 1; } return py; } function hufDecode(encodingTable, decodingTable, uInt8Array2, inDataView, inOffset, ni, rlc, no, outBuffer, outOffset) { var c = 0; var lc = 0; var outBufferEndOffset = no; var inOffsetEnd = Math.trunc(inOffset.value + (ni + 7) / 8); while (inOffset.value < inOffsetEnd) { getChar(c, lc, uInt8Array2, inOffset); c = getCharReturn.c; lc = getCharReturn.lc; while (lc >= HUF_DECBITS) { var pl = decodingTable[c >> lc - HUF_DECBITS & HUF_DECMASK]; if (pl.len) { lc -= pl.len; getCode(pl.lit, rlc, c, lc, uInt8Array2, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset); c = getCodeReturn.c; lc = getCodeReturn.lc; } else { if (!pl.p) throw "hufDecode issues"; var j; for (j = 0; j < pl.lit; j++) { var l = hufLength(encodingTable[pl.p[j]]); while (lc < l && inOffset.value < inOffsetEnd) { getChar(c, lc, uInt8Array2, inOffset); c = getCharReturn.c; lc = getCharReturn.lc; } if (lc >= l) { if (hufCode(encodingTable[pl.p[j]]) == (c >> lc - l & (1 << l) - 1)) { lc -= l; getCode(pl.p[j], rlc, c, lc, uInt8Array2, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset); c = getCodeReturn.c; lc = getCodeReturn.lc; break; } } } if (j == pl.lit) throw "hufDecode issues"; } } } var i = 8 - ni & 7; c >>= i; lc -= i; while (lc > 0) { var pl = decodingTable[c << HUF_DECBITS - lc & HUF_DECMASK]; if (pl.len) { lc -= pl.len; getCode(pl.lit, rlc, c, lc, uInt8Array2, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset); c = getCodeReturn.c; lc = getCodeReturn.lc; } else throw "hufDecode issues"; } return true; } function hufUncompress(uInt8Array2, inDataView, inOffset, nCompressed, outBuffer, nRaw) { var outOffset = { value: 0 }; var initialInOffset = inOffset.value; var im = parseUint32(inDataView, inOffset); var iM = parseUint32(inDataView, inOffset); inOffset.value += 4; var nBits = parseUint32(inDataView, inOffset); inOffset.value += 4; if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) throw "Something wrong with HUF_ENCSIZE"; var freq = new Array(HUF_ENCSIZE); var hdec = new Array(HUF_DECSIZE); hufClearDecTable(hdec); hufUnpackEncTable(uInt8Array2, inDataView, inOffset, nCompressed - (inOffset.value - initialInOffset), im, iM, freq); if (nBits > 8 * (nCompressed - (inOffset.value - initialInOffset))) throw "Something wrong with hufUncompress"; hufBuildDecTable(freq, im, iM, hdec); hufDecode(freq, hdec, uInt8Array2, inDataView, inOffset, nBits, iM, nRaw, outBuffer, outOffset); } function applyLut(lut, data, nData) { for (var i = 0; i < nData; ++i) data[i] = lut[data[i]]; } function predictor(source) { for (var t = 1; t < source.length; t++) source[t] = source[t - 1] + source[t] - 128; } function interleaveScalar(source, out) { var t1 = 0; var t2 = Math.floor((source.length + 1) / 2); var s = 0; var stop = source.length - 1; while (true) { if (s > stop) break; out[s++] = source[t1++]; if (s > stop) break; out[s++] = source[t2++]; } } function decodeRunLength(source) { var size = source.byteLength; var out = new Array(); var p = 0; var reader = new DataView(source); while (size > 0) { var l = reader.getInt8(p++); if (l < 0) { var count = -l; size -= count + 1; for (var i = 0; i < count; i++) out.push(reader.getUint8(p++)); } else { var count = l; size -= 2; var value = reader.getUint8(p++); for (var i = 0; i < count + 1; i++) out.push(value); } } return out; } function lossyDctDecode(cscSet, rowPtrs, channelData, acBuffer, dcBuffer, outBuffer) { var dataView = new DataView(outBuffer.buffer); var width = channelData[cscSet.idx[0]].width; var height = channelData[cscSet.idx[0]].height; var numComp = 3; var numFullBlocksX = Math.floor(width / 8); var numBlocksX = Math.ceil(width / 8); var numBlocksY = Math.ceil(height / 8); var leftoverX = width - (numBlocksX - 1) * 8; var leftoverY = height - (numBlocksY - 1) * 8; var currAcComp = { value: 0 }; var currDcComp = new Array(numComp); var dctData = new Array(numComp); var halfZigBlock = new Array(numComp); var rowBlock = new Array(numComp); var rowOffsets = new Array(numComp); for (let comp2 = 0; comp2 < numComp; ++comp2) { rowOffsets[comp2] = rowPtrs[cscSet.idx[comp2]]; currDcComp[comp2] = comp2 < 1 ? 0 : currDcComp[comp2 - 1] + numBlocksX * numBlocksY; dctData[comp2] = new Float32Array(64); halfZigBlock[comp2] = new Uint16Array(64); rowBlock[comp2] = new Uint16Array(numBlocksX * 64); } for (let blocky = 0; blocky < numBlocksY; ++blocky) { var maxY = 8; if (blocky == numBlocksY - 1) maxY = leftoverY; var maxX = 8; for (let blockx = 0; blockx < numBlocksX; ++blockx) { if (blockx == numBlocksX - 1) maxX = leftoverX; for (let comp2 = 0; comp2 < numComp; ++comp2) { halfZigBlock[comp2].fill(0); halfZigBlock[comp2][0] = dcBuffer[currDcComp[comp2]++]; unRleAC(currAcComp, acBuffer, halfZigBlock[comp2]); unZigZag(halfZigBlock[comp2], dctData[comp2]); dctInverse(dctData[comp2]); } csc709Inverse(dctData); for (let comp2 = 0; comp2 < numComp; ++comp2) convertToHalf(dctData[comp2], rowBlock[comp2], blockx * 64); } let offset2 = 0; for (let comp2 = 0; comp2 < numComp; ++comp2) { const type2 = channelData[cscSet.idx[comp2]].type; for (let y2 = 8 * blocky; y2 < 8 * blocky + maxY; ++y2) { offset2 = rowOffsets[comp2][y2]; for (let blockx = 0; blockx < numFullBlocksX; ++blockx) { const src = blockx * 64 + (y2 & 7) * 8; dataView.setUint16(offset2 + 0 * INT16_SIZE * type2, rowBlock[comp2][src + 0], true); dataView.setUint16(offset2 + 1 * INT16_SIZE * type2, rowBlock[comp2][src + 1], true); dataView.setUint16(offset2 + 2 * INT16_SIZE * type2, rowBlock[comp2][src + 2], true); dataView.setUint16(offset2 + 3 * INT16_SIZE * type2, rowBlock[comp2][src + 3], true); dataView.setUint16(offset2 + 4 * INT16_SIZE * type2, rowBlock[comp2][src + 4], true); dataView.setUint16(offset2 + 5 * INT16_SIZE * type2, rowBlock[comp2][src + 5], true); dataView.setUint16(offset2 + 6 * INT16_SIZE * type2, rowBlock[comp2][src + 6], true); dataView.setUint16(offset2 + 7 * INT16_SIZE * type2, rowBlock[comp2][src + 7], true); offset2 += 8 * INT16_SIZE * type2; } } if (numFullBlocksX != numBlocksX) for (let y2 = 8 * blocky; y2 < 8 * blocky + maxY; ++y2) { const offset3 = rowOffsets[comp2][y2] + 8 * numFullBlocksX * INT16_SIZE * type2; const src = numFullBlocksX * 64 + (y2 & 7) * 8; for (let x2 = 0; x2 < maxX; ++x2) dataView.setUint16(offset3 + x2 * INT16_SIZE * type2, rowBlock[comp2][src + x2], true); } } } var halfRow = new Uint16Array(width); var dataView = new DataView(outBuffer.buffer); for (var comp = 0; comp < numComp; ++comp) { channelData[cscSet.idx[comp]].decoded = true; var type = channelData[cscSet.idx[comp]].type; if (channelData[comp].type != 2) continue; for (var y = 0; y < height; ++y) { const offset2 = rowOffsets[comp][y]; for (var x = 0; x < width; ++x) halfRow[x] = dataView.getUint16(offset2 + x * INT16_SIZE * type, true); for (var x = 0; x < width; ++x) dataView.setFloat32(offset2 + x * INT16_SIZE * type, decodeFloat16(halfRow[x]), true); } } } function unRleAC(currAcComp, acBuffer, halfZigBlock) { var acValue; var dctComp = 1; while (dctComp < 64) { acValue = acBuffer[currAcComp.value]; if (acValue == 65280) dctComp = 64; else if (acValue >> 8 == 255) dctComp += acValue & 255; else { halfZigBlock[dctComp] = acValue; dctComp++; } currAcComp.value++; } } function unZigZag(src, dst) { dst[0] = decodeFloat16(src[0]); dst[1] = decodeFloat16(src[1]); dst[2] = decodeFloat16(src[5]); dst[3] = decodeFloat16(src[6]); dst[4] = decodeFloat16(src[14]); dst[5] = decodeFloat16(src[15]); dst[6] = decodeFloat16(src[27]); dst[7] = decodeFloat16(src[28]); dst[8] = decodeFloat16(src[2]); dst[9] = decodeFloat16(src[4]); dst[10] = decodeFloat16(src[7]); dst[11] = decodeFloat16(src[13]); dst[12] = decodeFloat16(src[16]); dst[13] = decodeFloat16(src[26]); dst[14] = decodeFloat16(src[29]); dst[15] = decodeFloat16(src[42]); dst[16] = decodeFloat16(src[3]); dst[17] = decodeFloat16(src[8]); dst[18] = decodeFloat16(src[12]); dst[19] = decodeFloat16(src[17]); dst[20] = decodeFloat16(src[25]); dst[21] = decodeFloat16(src[30]); dst[22] = decodeFloat16(src[41]); dst[23] = decodeFloat16(src[43]); dst[24] = decodeFloat16(src[9]); dst[25] = decodeFloat16(src[11]); dst[26] = decodeFloat16(src[18]); dst[27] = decodeFloat16(src[24]); dst[28] = decodeFloat16(src[31]); dst[29] = decodeFloat16(src[40]); dst[30] = decodeFloat16(src[44]); dst[31] = decodeFloat16(src[53]); dst[32] = decodeFloat16(src[10]); dst[33] = decodeFloat16(src[19]); dst[34] = decodeFloat16(src[23]); dst[35] = decodeFloat16(src[32]); dst[36] = decodeFloat16(src[39]); dst[37] = decodeFloat16(src[45]); dst[38] = decodeFloat16(src[52]); dst[39] = decodeFloat16(src[54]); dst[40] = decodeFloat16(src[20]); dst[41] = decodeFloat16(src[22]); dst[42] = decodeFloat16(src[33]); dst[43] = decodeFloat16(src[38]); dst[44] = decodeFloat16(src[46]); dst[45] = decodeFloat16(src[51]); dst[46] = decodeFloat16(src[55]); dst[47] = decodeFloat16(src[60]); dst[48] = decodeFloat16(src[21]); dst[49] = decodeFloat16(src[34]); dst[50] = decodeFloat16(src[37]); dst[51] = decodeFloat16(src[47]); dst[52] = decodeFloat16(src[50]); dst[53] = decodeFloat16(src[56]); dst[54] = decodeFloat16(src[59]); dst[55] = decodeFloat16(src[61]); dst[56] = decodeFloat16(src[35]); dst[57] = decodeFloat16(src[36]); dst[58] = decodeFloat16(src[48]); dst[59] = decodeFloat16(src[49]); dst[60] = decodeFloat16(src[57]); dst[61] = decodeFloat16(src[58]); dst[62] = decodeFloat16(src[62]); dst[63] = decodeFloat16(src[63]); } function dctInverse(data) { const a = .5 * Math.cos(3.14159 / 4); const b = .5 * Math.cos(3.14159 / 16); const c = .5 * Math.cos(3.14159 / 8); const d = .5 * Math.cos(3 * 3.14159 / 16); const e = .5 * Math.cos(5 * 3.14159 / 16); const f = .5 * Math.cos(3 * 3.14159 / 8); const g = .5 * Math.cos(7 * 3.14159 / 16); var alpha = new Array(4); var beta = new Array(4); var theta = new Array(4); var gamma = new Array(4); for (var row = 0; row < 8; ++row) { var rowPtr = row * 8; alpha[0] = c * data[rowPtr + 2]; alpha[1] = f * data[rowPtr + 2]; alpha[2] = c * data[rowPtr + 6]; alpha[3] = f * data[rowPtr + 6]; beta[0] = b * data[rowPtr + 1] + d * data[rowPtr + 3] + e * data[rowPtr + 5] + g * data[rowPtr + 7]; beta[1] = d * data[rowPtr + 1] - g * data[rowPtr + 3] - b * data[rowPtr + 5] - e * data[rowPtr + 7]; beta[2] = e * data[rowPtr + 1] - b * data[rowPtr + 3] + g * data[rowPtr + 5] + d * data[rowPtr + 7]; beta[3] = g * data[rowPtr + 1] - e * data[rowPtr + 3] + d * data[rowPtr + 5] - b * data[rowPtr + 7]; theta[0] = a * (data[rowPtr + 0] + data[rowPtr + 4]); theta[3] = a * (data[rowPtr + 0] - data[rowPtr + 4]); theta[1] = alpha[0] + alpha[3]; theta[2] = alpha[1] - alpha[2]; gamma[0] = theta[0] + theta[1]; gamma[1] = theta[3] + theta[2]; gamma[2] = theta[3] - theta[2]; gamma[3] = theta[0] - theta[1]; data[rowPtr + 0] = gamma[0] + beta[0]; data[rowPtr + 1] = gamma[1] + beta[1]; data[rowPtr + 2] = gamma[2] + beta[2]; data[rowPtr + 3] = gamma[3] + beta[3]; data[rowPtr + 4] = gamma[3] - beta[3]; data[rowPtr + 5] = gamma[2] - beta[2]; data[rowPtr + 6] = gamma[1] - beta[1]; data[rowPtr + 7] = gamma[0] - beta[0]; } for (var column = 0; column < 8; ++column) { alpha[0] = c * data[16 + column]; alpha[1] = f * data[16 + column]; alpha[2] = c * data[48 + column]; alpha[3] = f * data[48 + column]; beta[0] = b * data[8 + column] + d * data[24 + column] + e * data[40 + column] + g * data[56 + column]; beta[1] = d * data[8 + column] - g * data[24 + column] - b * data[40 + column] - e * data[56 + column]; beta[2] = e * data[8 + column] - b * data[24 + column] + g * data[40 + column] + d * data[56 + column]; beta[3] = g * data[8 + column] - e * data[24 + column] + d * data[40 + column] - b * data[56 + column]; theta[0] = a * (data[column] + data[32 + column]); theta[3] = a * (data[column] - data[32 + column]); theta[1] = alpha[0] + alpha[3]; theta[2] = alpha[1] - alpha[2]; gamma[0] = theta[0] + theta[1]; gamma[1] = theta[3] + theta[2]; gamma[2] = theta[3] - theta[2]; gamma[3] = theta[0] - theta[1]; data[0 + column] = gamma[0] + beta[0]; data[8 + column] = gamma[1] + beta[1]; data[16 + column] = gamma[2] + beta[2]; data[24 + column] = gamma[3] + beta[3]; data[32 + column] = gamma[3] - beta[3]; data[40 + column] = gamma[2] - beta[2]; data[48 + column] = gamma[1] - beta[1]; data[56 + column] = gamma[0] - beta[0]; } } function csc709Inverse(data) { for (var i = 0; i < 64; ++i) { var y = data[0][i]; var cb = data[1][i]; var cr = data[2][i]; data[0][i] = y + 1.5747 * cr; data[1][i] = y - .1873 * cb - .4682 * cr; data[2][i] = y + 1.8556 * cb; } } function convertToHalf(src, dst, idx) { for (var i = 0; i < 64; ++i) dst[idx + i] = DataUtils.toHalfFloat(toLinear(src[i])); } function toLinear(float) { if (float <= 1) return Math.sign(float) * Math.pow(Math.abs(float), 2.2); else return Math.sign(float) * Math.pow(logBase, Math.abs(float) - 1); } function uncompressRAW(info) { return new DataView(info.array.buffer, info.offset.value, info.size); } function uncompressRLE(info) { var compressed = info.viewer.buffer.slice(info.offset.value, info.offset.value + info.size); var rawBuffer = new Uint8Array(decodeRunLength(compressed)); var tmpBuffer = new Uint8Array(rawBuffer.length); predictor(rawBuffer); interleaveScalar(rawBuffer, tmpBuffer); return new DataView(tmpBuffer.buffer); } function uncompressZIP(info) { var rawBuffer = unzlibSync(info.array.slice(info.offset.value, info.offset.value + info.size)); var tmpBuffer = new Uint8Array(rawBuffer.length); predictor(rawBuffer); interleaveScalar(rawBuffer, tmpBuffer); return new DataView(tmpBuffer.buffer); } function uncompressPIZ(info) { var inDataView = info.viewer; var inOffset = { value: info.offset.value }; var outBuffer = new Uint16Array(info.width * info.scanlineBlockSize * (info.channels * info.type)); var bitmap = new Uint8Array(BITMAP_SIZE); var outBufferEnd = 0; var pizChannelData = new Array(info.channels); for (var i = 0; i < info.channels; i++) { pizChannelData[i] = {}; pizChannelData[i]["start"] = outBufferEnd; pizChannelData[i]["end"] = pizChannelData[i]["start"]; pizChannelData[i]["nx"] = info.width; pizChannelData[i]["ny"] = info.lines; pizChannelData[i]["size"] = info.type; outBufferEnd += pizChannelData[i].nx * pizChannelData[i].ny * pizChannelData[i].size; } var minNonZero = parseUint16(inDataView, inOffset); var maxNonZero = parseUint16(inDataView, inOffset); if (maxNonZero >= BITMAP_SIZE) throw "Something is wrong with PIZ_COMPRESSION BITMAP_SIZE"; if (minNonZero <= maxNonZero) for (var i = 0; i < maxNonZero - minNonZero + 1; i++) bitmap[i + minNonZero] = parseUint8(inDataView, inOffset); var lut = new Uint16Array(USHORT_RANGE); var maxValue = reverseLutFromBitmap(bitmap, lut); var length = parseUint32(inDataView, inOffset); hufUncompress(info.array, inDataView, inOffset, length, outBuffer, outBufferEnd); for (var i = 0; i < info.channels; ++i) { var cd = pizChannelData[i]; for (var j = 0; j < pizChannelData[i].size; ++j) wav2Decode(outBuffer, cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, maxValue); } applyLut(lut, outBuffer, outBufferEnd); var tmpOffset2 = 0; var tmpBuffer = new Uint8Array(outBuffer.buffer.byteLength); for (var y = 0; y < info.lines; y++) for (var c = 0; c < info.channels; c++) { var cd = pizChannelData[c]; var n = cd.nx * cd.size; var cp = new Uint8Array(outBuffer.buffer, cd.end * INT16_SIZE, n * INT16_SIZE); tmpBuffer.set(cp, tmpOffset2); tmpOffset2 += n * INT16_SIZE; cd.end += n; } return new DataView(tmpBuffer.buffer); } function uncompressPXR(info) { var rawBuffer = unzlibSync(info.array.slice(info.offset.value, info.offset.value + info.size)); const sz = info.lines * info.channels * info.width; const tmpBuffer = info.type == 1 ? new Uint16Array(sz) : new Uint32Array(sz); let tmpBufferEnd = 0; let writePtr = 0; const ptr = new Array(4); for (let y = 0; y < info.lines; y++) for (let c = 0; c < info.channels; c++) { let pixel = 0; switch (info.type) { case 1: ptr[0] = tmpBufferEnd; ptr[1] = ptr[0] + info.width; tmpBufferEnd = ptr[1] + info.width; for (let j = 0; j < info.width; ++j) { const diff = rawBuffer[ptr[0]++] << 8 | rawBuffer[ptr[1]++]; pixel += diff; tmpBuffer[writePtr] = pixel; writePtr++; } break; case 2: ptr[0] = tmpBufferEnd; ptr[1] = ptr[0] + info.width; ptr[2] = ptr[1] + info.width; tmpBufferEnd = ptr[2] + info.width; for (let j = 0; j < info.width; ++j) { const diff = rawBuffer[ptr[0]++] << 24 | rawBuffer[ptr[1]++] << 16 | rawBuffer[ptr[2]++] << 8; pixel += diff; tmpBuffer[writePtr] = pixel; writePtr++; } break; } } return new DataView(tmpBuffer.buffer); } function uncompressDWA(info) { var inDataView = info.viewer; var inOffset = { value: info.offset.value }; var outBuffer = new Uint8Array(info.width * info.lines * (info.channels * info.type * INT16_SIZE)); var dwaHeader = { version: parseInt64(inDataView, inOffset), unknownUncompressedSize: parseInt64(inDataView, inOffset), unknownCompressedSize: parseInt64(inDataView, inOffset), acCompressedSize: parseInt64(inDataView, inOffset), dcCompressedSize: parseInt64(inDataView, inOffset), rleCompressedSize: parseInt64(inDataView, inOffset), rleUncompressedSize: parseInt64(inDataView, inOffset), rleRawSize: parseInt64(inDataView, inOffset), totalAcUncompressedCount: parseInt64(inDataView, inOffset), totalDcUncompressedCount: parseInt64(inDataView, inOffset), acCompression: parseInt64(inDataView, inOffset) }; if (dwaHeader.version < 2) throw "EXRLoader.parse: " + EXRHeader.compression + " version " + dwaHeader.version + " is unsupported"; var channelRules = new Array(); var ruleSize = parseUint16(inDataView, inOffset) - INT16_SIZE; while (ruleSize > 0) { var name = parseNullTerminatedString(inDataView.buffer, inOffset); var value = parseUint8(inDataView, inOffset); var compression = value >> 2 & 3; var csc = (value >> 4) - 1; var index = new Int8Array([csc])[0]; var type = parseUint8(inDataView, inOffset); channelRules.push({ name, index, type, compression }); ruleSize -= name.length + 3; } var channels = EXRHeader.channels; var channelData = new Array(info.channels); for (var i = 0; i < info.channels; ++i) { var cd = channelData[i] = {}; var channel = channels[i]; cd.name = channel.name; cd.compression = UNKNOWN; cd.decoded = false; cd.type = channel.pixelType; cd.pLinear = channel.pLinear; cd.width = info.width; cd.height = info.lines; } var cscSet = { idx: new Array(3) }; for (var offset2 = 0; offset2 < info.channels; ++offset2) { var cd = channelData[offset2]; for (var i = 0; i < channelRules.length; ++i) { var rule = channelRules[i]; if (cd.name == rule.name) { cd.compression = rule.compression; if (rule.index >= 0) cscSet.idx[rule.index] = offset2; cd.offset = offset2; } } } if (dwaHeader.acCompressedSize > 0) switch (dwaHeader.acCompression) { case STATIC_HUFFMAN: var acBuffer = new Uint16Array(dwaHeader.totalAcUncompressedCount); hufUncompress(info.array, inDataView, inOffset, dwaHeader.acCompressedSize, acBuffer, dwaHeader.totalAcUncompressedCount); break; case DEFLATE: var compressed = info.array.slice(inOffset.value, inOffset.value + dwaHeader.totalAcUncompressedCount); var data = unzlibSync(compressed); var acBuffer = new Uint16Array(data.buffer); inOffset.value += dwaHeader.totalAcUncompressedCount; break; } if (dwaHeader.dcCompressedSize > 0) { var zlibInfo = { array: info.array, offset: inOffset, size: dwaHeader.dcCompressedSize }; var dcBuffer = new Uint16Array(uncompressZIP(zlibInfo).buffer); inOffset.value += dwaHeader.dcCompressedSize; } if (dwaHeader.rleRawSize > 0) { var compressed = info.array.slice(inOffset.value, inOffset.value + dwaHeader.rleCompressedSize); var data = unzlibSync(compressed); var rleBuffer = decodeRunLength(data.buffer); inOffset.value += dwaHeader.rleCompressedSize; } var outBufferEnd = 0; var rowOffsets = new Array(channelData.length); for (var i = 0; i < rowOffsets.length; ++i) rowOffsets[i] = new Array(); for (var y = 0; y < info.lines; ++y) for (var chan = 0; chan < channelData.length; ++chan) { rowOffsets[chan].push(outBufferEnd); outBufferEnd += channelData[chan].width * info.type * INT16_SIZE; } lossyDctDecode(cscSet, rowOffsets, channelData, acBuffer, dcBuffer, outBuffer); for (var i = 0; i < channelData.length; ++i) { var cd = channelData[i]; if (cd.decoded) continue; switch (cd.compression) { case RLE: var row = 0; var rleOffset = 0; for (var y = 0; y < info.lines; ++y) { var rowOffsetBytes = rowOffsets[i][row]; for (var x = 0; x < cd.width; ++x) { for (var byte = 0; byte < INT16_SIZE * cd.type; ++byte) outBuffer[rowOffsetBytes++] = rleBuffer[rleOffset + byte * cd.width * cd.height]; rleOffset++; } row++; } break; case LOSSY_DCT: default: throw "EXRLoader.parse: unsupported channel compression"; } } return new DataView(outBuffer.buffer); } function parseNullTerminatedString(buffer2, offset2) { var uintBuffer = new Uint8Array(buffer2); var endOffset = 0; while (uintBuffer[offset2.value + endOffset] != 0) endOffset += 1; var stringValue = new TextDecoder().decode(uintBuffer.slice(offset2.value, offset2.value + endOffset)); offset2.value = offset2.value + endOffset + 1; return stringValue; } function parseFixedLengthString(buffer2, offset2, size) { var stringValue = new TextDecoder().decode(new Uint8Array(buffer2).slice(offset2.value, offset2.value + size)); offset2.value = offset2.value + size; return stringValue; } function parseRational(dataView, offset2) { return [parseInt32(dataView, offset2), parseUint32(dataView, offset2)]; } function parseTimecode(dataView, offset2) { return [parseUint32(dataView, offset2), parseUint32(dataView, offset2)]; } function parseInt32(dataView, offset2) { var Int32 = dataView.getInt32(offset2.value, true); offset2.value = offset2.value + INT32_SIZE; return Int32; } function parseUint32(dataView, offset2) { var Uint32 = dataView.getUint32(offset2.value, true); offset2.value = offset2.value + INT32_SIZE; return Uint32; } function parseUint8Array(uInt8Array2, offset2) { var Uint8 = uInt8Array2[offset2.value]; offset2.value = offset2.value + INT8_SIZE; return Uint8; } function parseUint8(dataView, offset2) { var Uint8 = dataView.getUint8(offset2.value); offset2.value = offset2.value + INT8_SIZE; return Uint8; } const parseInt64 = function(dataView, offset2) { let int; if ("getBigInt64" in DataView.prototype) int = Number(dataView.getBigInt64(offset2.value, true)); else int = dataView.getUint32(offset2.value + 4, true) + Number(dataView.getUint32(offset2.value, true) << 32); offset2.value += ULONG_SIZE; return int; }; function parseFloat32(dataView, offset2) { var float = dataView.getFloat32(offset2.value, true); offset2.value += FLOAT32_SIZE; return float; } function decodeFloat32(dataView, offset2) { return DataUtils.toHalfFloat(parseFloat32(dataView, offset2)); } function decodeFloat16(binary) { var exponent = (binary & 31744) >> 10, fraction = binary & 1023; return (binary >> 15 ? -1 : 1) * (exponent ? exponent === 31 ? fraction ? NaN : Infinity : Math.pow(2, exponent - 15) * (1 + fraction / 1024) : 6103515625e-14 * (fraction / 1024)); } function parseUint16(dataView, offset2) { var Uint16 = dataView.getUint16(offset2.value, true); offset2.value += INT16_SIZE; return Uint16; } function parseFloat16(buffer2, offset2) { return decodeFloat16(parseUint16(buffer2, offset2)); } function parseChlist(dataView, buffer2, offset2, size) { var startOffset = offset2.value; var channels = []; while (offset2.value < startOffset + size - 1) { var name = parseNullTerminatedString(buffer2, offset2); var pixelType = parseInt32(dataView, offset2); var pLinear = parseUint8(dataView, offset2); offset2.value += 3; var xSampling = parseInt32(dataView, offset2); var ySampling = parseInt32(dataView, offset2); channels.push({ name, pixelType, pLinear, xSampling, ySampling }); } offset2.value += 1; return channels; } function parseChromaticities(dataView, offset2) { return { redX: parseFloat32(dataView, offset2), redY: parseFloat32(dataView, offset2), greenX: parseFloat32(dataView, offset2), greenY: parseFloat32(dataView, offset2), blueX: parseFloat32(dataView, offset2), blueY: parseFloat32(dataView, offset2), whiteX: parseFloat32(dataView, offset2), whiteY: parseFloat32(dataView, offset2) }; } function parseCompression(dataView, offset2) { return [ "NO_COMPRESSION", "RLE_COMPRESSION", "ZIPS_COMPRESSION", "ZIP_COMPRESSION", "PIZ_COMPRESSION", "PXR24_COMPRESSION", "B44_COMPRESSION", "B44A_COMPRESSION", "DWAA_COMPRESSION", "DWAB_COMPRESSION" ][parseUint8(dataView, offset2)]; } function parseBox2i(dataView, offset2) { return { xMin: parseUint32(dataView, offset2), yMin: parseUint32(dataView, offset2), xMax: parseUint32(dataView, offset2), yMax: parseUint32(dataView, offset2) }; } function parseLineOrder(dataView, offset2) { return ["INCREASING_Y"][parseUint8(dataView, offset2)]; } function parseV2f(dataView, offset2) { return [parseFloat32(dataView, offset2), parseFloat32(dataView, offset2)]; } function parseV3f(dataView, offset2) { return [ parseFloat32(dataView, offset2), parseFloat32(dataView, offset2), parseFloat32(dataView, offset2) ]; } function parseValue(dataView, buffer2, offset2, type, size) { if (type === "string" || type === "stringvector" || type === "iccProfile") return parseFixedLengthString(buffer2, offset2, size); else if (type === "chlist") return parseChlist(dataView, buffer2, offset2, size); else if (type === "chromaticities") return parseChromaticities(dataView, offset2); else if (type === "compression") return parseCompression(dataView, offset2); else if (type === "box2i") return parseBox2i(dataView, offset2); else if (type === "lineOrder") return parseLineOrder(dataView, offset2); else if (type === "float") return parseFloat32(dataView, offset2); else if (type === "v2f") return parseV2f(dataView, offset2); else if (type === "v3f") return parseV3f(dataView, offset2); else if (type === "int") return parseInt32(dataView, offset2); else if (type === "rational") return parseRational(dataView, offset2); else if (type === "timecode") return parseTimecode(dataView, offset2); else if (type === "preview") { offset2.value += size; return "skipped"; } else { offset2.value += size; return; } } function parseHeader(dataView, buffer2, offset2) { const EXRHeader2 = {}; if (dataView.getUint32(0, true) != 20000630) throw "THREE.EXRLoader: provided file doesn't appear to be in OpenEXR format."; EXRHeader2.version = dataView.getUint8(4); const spec = dataView.getUint8(5); EXRHeader2.spec = { singleTile: !!(spec & 2), longName: !!(spec & 4), deepFormat: !!(spec & 8), multiPart: !!(spec & 16) }; offset2.value = 8; var keepReading = true; while (keepReading) { var attributeName = parseNullTerminatedString(buffer2, offset2); if (attributeName == 0) keepReading = false; else { var attributeType = parseNullTerminatedString(buffer2, offset2); var attributeValue = parseValue(dataView, buffer2, offset2, attributeType, parseUint32(dataView, offset2)); if (attributeValue === void 0) console.warn(`EXRLoader.parse: skipped unknown header attribute type '${attributeType}'.`); else EXRHeader2[attributeName] = attributeValue; } } if ((spec & -5) != 0) { console.error("EXRHeader:", EXRHeader2); throw "THREE.EXRLoader: provided file is currently unsupported."; } return EXRHeader2; } function setupDecoder(EXRHeader2, dataView, uInt8Array2, offset2, outputType) { const EXRDecoder2 = { size: 0, viewer: dataView, array: uInt8Array2, offset: offset2, width: EXRHeader2.dataWindow.xMax - EXRHeader2.dataWindow.xMin + 1, height: EXRHeader2.dataWindow.yMax - EXRHeader2.dataWindow.yMin + 1, channels: EXRHeader2.channels.length, bytesPerLine: null, lines: null, inputSize: null, type: EXRHeader2.channels[0].pixelType, uncompress: null, getter: null, format: null, [hasColorSpace ? "colorSpace" : "encoding"]: null }; switch (EXRHeader2.compression) { case "NO_COMPRESSION": EXRDecoder2.lines = 1; EXRDecoder2.uncompress = uncompressRAW; break; case "RLE_COMPRESSION": EXRDecoder2.lines = 1; EXRDecoder2.uncompress = uncompressRLE; break; case "ZIPS_COMPRESSION": EXRDecoder2.lines = 1; EXRDecoder2.uncompress = uncompressZIP; break; case "ZIP_COMPRESSION": EXRDecoder2.lines = 16; EXRDecoder2.uncompress = uncompressZIP; break; case "PIZ_COMPRESSION": EXRDecoder2.lines = 32; EXRDecoder2.uncompress = uncompressPIZ; break; case "PXR24_COMPRESSION": EXRDecoder2.lines = 16; EXRDecoder2.uncompress = uncompressPXR; break; case "DWAA_COMPRESSION": EXRDecoder2.lines = 32; EXRDecoder2.uncompress = uncompressDWA; break; case "DWAB_COMPRESSION": EXRDecoder2.lines = 256; EXRDecoder2.uncompress = uncompressDWA; break; default: throw "EXRLoader.parse: " + EXRHeader2.compression + " is unsupported"; } EXRDecoder2.scanlineBlockSize = EXRDecoder2.lines; if (EXRDecoder2.type == 1) switch (outputType) { case FloatType: EXRDecoder2.getter = parseFloat16; EXRDecoder2.inputSize = INT16_SIZE; break; case HalfFloatType: EXRDecoder2.getter = parseUint16; EXRDecoder2.inputSize = INT16_SIZE; break; } else if (EXRDecoder2.type == 2) switch (outputType) { case FloatType: EXRDecoder2.getter = parseFloat32; EXRDecoder2.inputSize = FLOAT32_SIZE; break; case HalfFloatType: EXRDecoder2.getter = decodeFloat32; EXRDecoder2.inputSize = FLOAT32_SIZE; } else throw "EXRLoader.parse: unsupported pixelType " + EXRDecoder2.type + " for " + EXRHeader2.compression + "."; EXRDecoder2.blockCount = (EXRHeader2.dataWindow.yMax + 1) / EXRDecoder2.scanlineBlockSize; for (var i = 0; i < EXRDecoder2.blockCount; i++) parseInt64(dataView, offset2); EXRDecoder2.outputChannels = EXRDecoder2.channels == 3 ? 4 : EXRDecoder2.channels; const size = EXRDecoder2.width * EXRDecoder2.height * EXRDecoder2.outputChannels; switch (outputType) { case FloatType: EXRDecoder2.byteArray = new Float32Array(size); if (EXRDecoder2.channels < EXRDecoder2.outputChannels) EXRDecoder2.byteArray.fill(1, 0, size); break; case HalfFloatType: EXRDecoder2.byteArray = new Uint16Array(size); if (EXRDecoder2.channels < EXRDecoder2.outputChannels) EXRDecoder2.byteArray.fill(15360, 0, size); break; default: console.error("THREE.EXRLoader: unsupported type: ", outputType); break; } EXRDecoder2.bytesPerLine = EXRDecoder2.width * EXRDecoder2.inputSize * EXRDecoder2.channels; if (EXRDecoder2.outputChannels == 4) EXRDecoder2.format = RGBAFormat; else EXRDecoder2.format = RedFormat; if (hasColorSpace) EXRDecoder2.colorSpace = "srgb-linear"; else EXRDecoder2.encoding = 3e3; return EXRDecoder2; } const bufferDataView = new DataView(buffer); const uInt8Array = new Uint8Array(buffer); const offset = { value: 0 }; const EXRHeader = parseHeader(bufferDataView, buffer, offset); const EXRDecoder = setupDecoder(EXRHeader, bufferDataView, uInt8Array, offset, this.type); const tmpOffset = { value: 0 }; const channelOffsets = { R: 0, G: 1, B: 2, A: 3, Y: 0 }; for (let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.scanlineBlockSize; scanlineBlockIdx++) { const line = parseUint32(bufferDataView, offset); EXRDecoder.size = parseUint32(bufferDataView, offset); EXRDecoder.lines = line + EXRDecoder.scanlineBlockSize > EXRDecoder.height ? EXRDecoder.height - line : EXRDecoder.scanlineBlockSize; const viewer = EXRDecoder.size < EXRDecoder.lines * EXRDecoder.bytesPerLine ? EXRDecoder.uncompress(EXRDecoder) : uncompressRAW(EXRDecoder); offset.value += EXRDecoder.size; for (let line_y = 0; line_y < EXRDecoder.scanlineBlockSize; line_y++) { const true_y = line_y + scanlineBlockIdx * EXRDecoder.scanlineBlockSize; if (true_y >= EXRDecoder.height) break; for (let channelID = 0; channelID < EXRDecoder.channels; channelID++) { const cOff = channelOffsets[EXRHeader.channels[channelID].name]; for (let x = 0; x < EXRDecoder.width; x++) { tmpOffset.value = (line_y * (EXRDecoder.channels * EXRDecoder.width) + channelID * EXRDecoder.width + x) * EXRDecoder.inputSize; const outIndex = (EXRDecoder.height - 1 - true_y) * (EXRDecoder.width * EXRDecoder.outputChannels) + x * EXRDecoder.outputChannels + cOff; EXRDecoder.byteArray[outIndex] = EXRDecoder.getter(viewer, tmpOffset); } } } } return { header: EXRHeader, width: EXRDecoder.width, height: EXRDecoder.height, data: EXRDecoder.byteArray, format: EXRDecoder.format, [hasColorSpace ? "colorSpace" : "encoding"]: EXRDecoder[hasColorSpace ? "colorSpace" : "encoding"], type: this.type }; } setDataType(value) { this.type = value; return this; } load(url, onLoad, onProgress, onError) { function onLoadCallback(texture, texData) { if (hasColorSpace) texture.colorSpace = texData.colorSpace; else texture.encoding = texData.encoding; texture.minFilter = LinearFilter; texture.magFilter = LinearFilter; texture.generateMipmaps = false; texture.flipY = false; if (onLoad) onLoad(texture, texData); } return super.load(url, onLoadCallback, onProgress, onError); } }; //#endregion //#region node_modules/three-stdlib/loaders/SVGLoader.js var COLOR_SPACE_SVG = "srgb"; var SVGLoader = /* @__PURE__ */ (() => { class SVGLoader2 extends Loader$1 { constructor(manager) { super(manager); this.defaultDPI = 90; this.defaultUnit = "px"; } load(url, onLoad, onProgress, onError) { const scope = this; const loader = new FileLoader(scope.manager); loader.setPath(scope.path); loader.setRequestHeader(scope.requestHeader); loader.setWithCredentials(scope.withCredentials); loader.load(url, function(text) { try { onLoad(scope.parse(text)); } catch (e) { if (onError) onError(e); else console.error(e); scope.manager.itemError(url); } }, onProgress, onError); } parse(text) { const scope = this; function parseNode(node, style) { if (node.nodeType !== 1) return; const transform = getNodeTransform(node); let isDefsNode = false; let path = null; switch (node.nodeName) { case "svg": style = parseStyle(node, style); break; case "style": parseCSSStylesheet(node); break; case "g": style = parseStyle(node, style); break; case "path": style = parseStyle(node, style); if (node.hasAttribute("d")) path = parsePathNode(node); break; case "rect": style = parseStyle(node, style); path = parseRectNode(node); break; case "polygon": style = parseStyle(node, style); path = parsePolygonNode(node); break; case "polyline": style = parseStyle(node, style); path = parsePolylineNode(node); break; case "circle": style = parseStyle(node, style); path = parseCircleNode(node); break; case "ellipse": style = parseStyle(node, style); path = parseEllipseNode(node); break; case "line": style = parseStyle(node, style); path = parseLineNode(node); break; case "defs": isDefsNode = true; break; case "use": style = parseStyle(node, style); const usedNodeId = (node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "").substring(1); const usedNode = node.viewportElement.getElementById(usedNodeId); if (usedNode) parseNode(usedNode, style); else console.warn("SVGLoader: 'use node' references non-existent node id: " + usedNodeId); break; } if (path) { if (style.fill !== void 0 && style.fill !== "none") path.color.setStyle(style.fill, COLOR_SPACE_SVG); transformPath(path, currentTransform); paths.push(path); path.userData = { node, style }; } const childNodes = node.childNodes; for (let i = 0; i < childNodes.length; i++) { const node2 = childNodes[i]; if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs") continue; parseNode(node2, style); } if (transform) { transformStack.pop(); if (transformStack.length > 0) currentTransform.copy(transformStack[transformStack.length - 1]); else currentTransform.identity(); } } function parsePathNode(node) { const path = new ShapePath(); const point = new Vector2(); const control = new Vector2(); const firstPoint = new Vector2(); let isFirstPoint = true; let doSetFirstPoint = false; const d = node.getAttribute("d"); if (d === "" || d === "none") return null; const commands = d.match(/[a-df-z][^a-df-z]*/gi); for (let i = 0, l = commands.length; i < l; i++) { const command = commands[i]; const type = command.charAt(0); const data2 = command.slice(1).trim(); if (isFirstPoint === true) { doSetFirstPoint = true; isFirstPoint = false; } let numbers; switch (type) { case "M": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { point.x = numbers[j + 0]; point.y = numbers[j + 1]; control.x = point.x; control.y = point.y; if (j === 0) path.moveTo(point.x, point.y); else path.lineTo(point.x, point.y); if (j === 0) firstPoint.copy(point); } break; case "H": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j++) { point.x = numbers[j]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "V": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j++) { point.y = numbers[j]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "L": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { point.x = numbers[j + 0]; point.y = numbers[j + 1]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "C": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 6) { path.bezierCurveTo(numbers[j + 0], numbers[j + 1], numbers[j + 2], numbers[j + 3], numbers[j + 4], numbers[j + 5]); control.x = numbers[j + 2]; control.y = numbers[j + 3]; point.x = numbers[j + 4]; point.y = numbers[j + 5]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "S": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 4) { path.bezierCurveTo(getReflection(point.x, control.x), getReflection(point.y, control.y), numbers[j + 0], numbers[j + 1], numbers[j + 2], numbers[j + 3]); control.x = numbers[j + 0]; control.y = numbers[j + 1]; point.x = numbers[j + 2]; point.y = numbers[j + 3]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "Q": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 4) { path.quadraticCurveTo(numbers[j + 0], numbers[j + 1], numbers[j + 2], numbers[j + 3]); control.x = numbers[j + 0]; control.y = numbers[j + 1]; point.x = numbers[j + 2]; point.y = numbers[j + 3]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "T": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { const rx = getReflection(point.x, control.x); const ry = getReflection(point.y, control.y); path.quadraticCurveTo(rx, ry, numbers[j + 0], numbers[j + 1]); control.x = rx; control.y = ry; point.x = numbers[j + 0]; point.y = numbers[j + 1]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "A": numbers = parseFloats(data2, [3, 4], 7); for (let j = 0, jl = numbers.length; j < jl; j += 7) { if (numbers[j + 5] == point.x && numbers[j + 6] == point.y) continue; const start = point.clone(); point.x = numbers[j + 5]; point.y = numbers[j + 6]; control.x = point.x; control.y = point.y; parseArcCommand(path, numbers[j], numbers[j + 1], numbers[j + 2], numbers[j + 3], numbers[j + 4], start, point); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "m": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { point.x += numbers[j + 0]; point.y += numbers[j + 1]; control.x = point.x; control.y = point.y; if (j === 0) path.moveTo(point.x, point.y); else path.lineTo(point.x, point.y); if (j === 0) firstPoint.copy(point); } break; case "h": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j++) { point.x += numbers[j]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "v": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j++) { point.y += numbers[j]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "l": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { point.x += numbers[j + 0]; point.y += numbers[j + 1]; control.x = point.x; control.y = point.y; path.lineTo(point.x, point.y); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "c": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 6) { path.bezierCurveTo(point.x + numbers[j + 0], point.y + numbers[j + 1], point.x + numbers[j + 2], point.y + numbers[j + 3], point.x + numbers[j + 4], point.y + numbers[j + 5]); control.x = point.x + numbers[j + 2]; control.y = point.y + numbers[j + 3]; point.x += numbers[j + 4]; point.y += numbers[j + 5]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "s": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 4) { path.bezierCurveTo(getReflection(point.x, control.x), getReflection(point.y, control.y), point.x + numbers[j + 0], point.y + numbers[j + 1], point.x + numbers[j + 2], point.y + numbers[j + 3]); control.x = point.x + numbers[j + 0]; control.y = point.y + numbers[j + 1]; point.x += numbers[j + 2]; point.y += numbers[j + 3]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "q": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 4) { path.quadraticCurveTo(point.x + numbers[j + 0], point.y + numbers[j + 1], point.x + numbers[j + 2], point.y + numbers[j + 3]); control.x = point.x + numbers[j + 0]; control.y = point.y + numbers[j + 1]; point.x += numbers[j + 2]; point.y += numbers[j + 3]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "t": numbers = parseFloats(data2); for (let j = 0, jl = numbers.length; j < jl; j += 2) { const rx = getReflection(point.x, control.x); const ry = getReflection(point.y, control.y); path.quadraticCurveTo(rx, ry, point.x + numbers[j + 0], point.y + numbers[j + 1]); control.x = rx; control.y = ry; point.x = point.x + numbers[j + 0]; point.y = point.y + numbers[j + 1]; if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "a": numbers = parseFloats(data2, [3, 4], 7); for (let j = 0, jl = numbers.length; j < jl; j += 7) { if (numbers[j + 5] == 0 && numbers[j + 6] == 0) continue; const start = point.clone(); point.x += numbers[j + 5]; point.y += numbers[j + 6]; control.x = point.x; control.y = point.y; parseArcCommand(path, numbers[j], numbers[j + 1], numbers[j + 2], numbers[j + 3], numbers[j + 4], start, point); if (j === 0 && doSetFirstPoint === true) firstPoint.copy(point); } break; case "Z": case "z": path.currentPath.autoClose = true; if (path.currentPath.curves.length > 0) { point.copy(firstPoint); path.currentPath.currentPoint.copy(point); isFirstPoint = true; } break; default: console.warn(command); } doSetFirstPoint = false; } return path; } function parseCSSStylesheet(node) { if (!node.sheet || !node.sheet.cssRules || !node.sheet.cssRules.length) return; for (let i = 0; i < node.sheet.cssRules.length; i++) { const stylesheet = node.sheet.cssRules[i]; if (stylesheet.type !== 1) continue; const selectorList = stylesheet.selectorText.split(/,/gm).filter(Boolean).map((i2) => i2.trim()); for (let j = 0; j < selectorList.length; j++) { const definitions = Object.fromEntries(Object.entries(stylesheet.style).filter(([, v]) => v !== "")); stylesheets[selectorList[j]] = Object.assign(stylesheets[selectorList[j]] || {}, definitions); } } } function parseArcCommand(path, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, start, end) { if (rx == 0 || ry == 0) { path.lineTo(end.x, end.y); return; } x_axis_rotation = x_axis_rotation * Math.PI / 180; rx = Math.abs(rx); ry = Math.abs(ry); const dx2 = (start.x - end.x) / 2; const dy2 = (start.y - end.y) / 2; const x1p = Math.cos(x_axis_rotation) * dx2 + Math.sin(x_axis_rotation) * dy2; const y1p = -Math.sin(x_axis_rotation) * dx2 + Math.cos(x_axis_rotation) * dy2; let rxs = rx * rx; let rys = ry * ry; const x1ps = x1p * x1p; const y1ps = y1p * y1p; const cr = x1ps / rxs + y1ps / rys; if (cr > 1) { const s = Math.sqrt(cr); rx = s * rx; ry = s * ry; rxs = rx * rx; rys = ry * ry; } const dq = rxs * y1ps + rys * x1ps; const pq = (rxs * rys - dq) / dq; let q = Math.sqrt(Math.max(0, pq)); if (large_arc_flag === sweep_flag) q = -q; const cxp = q * rx * y1p / ry; const cyp = -q * ry * x1p / rx; const cx = Math.cos(x_axis_rotation) * cxp - Math.sin(x_axis_rotation) * cyp + (start.x + end.x) / 2; const cy = Math.sin(x_axis_rotation) * cxp + Math.cos(x_axis_rotation) * cyp + (start.y + end.y) / 2; const theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry); const delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry) % (Math.PI * 2); path.currentPath.absellipse(cx, cy, rx, ry, theta, theta + delta, sweep_flag === 0, x_axis_rotation); } function svgAngle(ux, uy, vx, vy) { const dot = ux * vx + uy * vy; const len = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy); let ang = Math.acos(Math.max(-1, Math.min(1, dot / len))); if (ux * vy - uy * vx < 0) ang = -ang; return ang; } function parseRectNode(node) { const x = parseFloatWithUnits(node.getAttribute("x") || 0); const y = parseFloatWithUnits(node.getAttribute("y") || 0); const rx = parseFloatWithUnits(node.getAttribute("rx") || node.getAttribute("ry") || 0); const ry = parseFloatWithUnits(node.getAttribute("ry") || node.getAttribute("rx") || 0); const w = parseFloatWithUnits(node.getAttribute("width")); const h = parseFloatWithUnits(node.getAttribute("height")); const bci = .448084975506; const path = new ShapePath(); path.moveTo(x + rx, y); path.lineTo(x + w - rx, y); if (rx !== 0 || ry !== 0) path.bezierCurveTo(x + w - rx * bci, y, x + w, y + ry * bci, x + w, y + ry); path.lineTo(x + w, y + h - ry); if (rx !== 0 || ry !== 0) path.bezierCurveTo(x + w, y + h - ry * bci, x + w - rx * bci, y + h, x + w - rx, y + h); path.lineTo(x + rx, y + h); if (rx !== 0 || ry !== 0) path.bezierCurveTo(x + rx * bci, y + h, x, y + h - ry * bci, x, y + h - ry); path.lineTo(x, y + ry); if (rx !== 0 || ry !== 0) path.bezierCurveTo(x, y + ry * bci, x + rx * bci, y, x + rx, y); return path; } function parsePolygonNode(node) { function iterator(match, a, b) { const x = parseFloatWithUnits(a); const y = parseFloatWithUnits(b); if (index === 0) path.moveTo(x, y); else path.lineTo(x, y); index++; } const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g; const path = new ShapePath(); let index = 0; node.getAttribute("points").replace(regex, iterator); path.currentPath.autoClose = true; return path; } function parsePolylineNode(node) { function iterator(match, a, b) { const x = parseFloatWithUnits(a); const y = parseFloatWithUnits(b); if (index === 0) path.moveTo(x, y); else path.lineTo(x, y); index++; } const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g; const path = new ShapePath(); let index = 0; node.getAttribute("points").replace(regex, iterator); path.currentPath.autoClose = false; return path; } function parseCircleNode(node) { const x = parseFloatWithUnits(node.getAttribute("cx") || 0); const y = parseFloatWithUnits(node.getAttribute("cy") || 0); const r = parseFloatWithUnits(node.getAttribute("r") || 0); const subpath = new Path(); subpath.absarc(x, y, r, 0, Math.PI * 2); const path = new ShapePath(); path.subPaths.push(subpath); return path; } function parseEllipseNode(node) { const x = parseFloatWithUnits(node.getAttribute("cx") || 0); const y = parseFloatWithUnits(node.getAttribute("cy") || 0); const rx = parseFloatWithUnits(node.getAttribute("rx") || 0); const ry = parseFloatWithUnits(node.getAttribute("ry") || 0); const subpath = new Path(); subpath.absellipse(x, y, rx, ry, 0, Math.PI * 2); const path = new ShapePath(); path.subPaths.push(subpath); return path; } function parseLineNode(node) { const x1 = parseFloatWithUnits(node.getAttribute("x1") || 0); const y1 = parseFloatWithUnits(node.getAttribute("y1") || 0); const x2 = parseFloatWithUnits(node.getAttribute("x2") || 0); const y2 = parseFloatWithUnits(node.getAttribute("y2") || 0); const path = new ShapePath(); path.moveTo(x1, y1); path.lineTo(x2, y2); path.currentPath.autoClose = false; return path; } function parseStyle(node, style) { style = Object.assign({}, style); let stylesheetStyles = {}; if (node.hasAttribute("class")) { const classSelectors = node.getAttribute("class").split(/\s/).filter(Boolean).map((i) => i.trim()); for (let i = 0; i < classSelectors.length; i++) stylesheetStyles = Object.assign(stylesheetStyles, stylesheets["." + classSelectors[i]]); } if (node.hasAttribute("id")) stylesheetStyles = Object.assign(stylesheetStyles, stylesheets["#" + node.getAttribute("id")]); function addStyle(svgName, jsName, adjustFunction) { if (adjustFunction === void 0) adjustFunction = function copy(v) { if (v.startsWith("url")) console.warn("SVGLoader: url access in attributes is not implemented."); return v; }; if (node.hasAttribute(svgName)) style[jsName] = adjustFunction(node.getAttribute(svgName)); if (stylesheetStyles[svgName]) style[jsName] = adjustFunction(stylesheetStyles[svgName]); if (node.style && node.style[svgName] !== "") style[jsName] = adjustFunction(node.style[svgName]); } function clamp(v) { return Math.max(0, Math.min(1, parseFloatWithUnits(v))); } function positive(v) { return Math.max(0, parseFloatWithUnits(v)); } addStyle("fill", "fill"); addStyle("fill-opacity", "fillOpacity", clamp); addStyle("fill-rule", "fillRule"); addStyle("opacity", "opacity", clamp); addStyle("stroke", "stroke"); addStyle("stroke-opacity", "strokeOpacity", clamp); addStyle("stroke-width", "strokeWidth", positive); addStyle("stroke-linejoin", "strokeLineJoin"); addStyle("stroke-linecap", "strokeLineCap"); addStyle("stroke-miterlimit", "strokeMiterLimit", positive); addStyle("visibility", "visibility"); return style; } function getReflection(a, b) { return a - (b - a); } function parseFloats(input, flags, stride) { if (typeof input !== "string") throw new TypeError("Invalid input: " + typeof input); const RE = { SEPARATOR: /[ \t\r\n\,.\-+]/, WHITESPACE: /[ \t\r\n]/, DIGIT: /[\d]/, SIGN: /[-+]/, POINT: /\./, COMMA: /,/, EXP: /e/i, FLAGS: /[01]/ }; const SEP = 0; const INT = 1; const FLOAT = 2; const EXP = 3; let state = SEP; let seenComma = true; let number = "", exponent = ""; const result = []; function throwSyntaxError(current2, i, partial) { const error = /* @__PURE__ */ new SyntaxError("Unexpected character \"" + current2 + "\" at index " + i + "."); error.partial = partial; throw error; } function newNumber() { if (number !== "") if (exponent === "") result.push(Number(number)); else result.push(Number(number) * Math.pow(10, Number(exponent))); number = ""; exponent = ""; } let current; const length = input.length; for (let i = 0; i < length; i++) { current = input[i]; if (Array.isArray(flags) && flags.includes(result.length % stride) && RE.FLAGS.test(current)) { state = INT; number = current; newNumber(); continue; } if (state === SEP) { if (RE.WHITESPACE.test(current)) continue; if (RE.DIGIT.test(current) || RE.SIGN.test(current)) { state = INT; number = current; continue; } if (RE.POINT.test(current)) { state = FLOAT; number = current; continue; } if (RE.COMMA.test(current)) { if (seenComma) throwSyntaxError(current, i, result); seenComma = true; } } if (state === INT) { if (RE.DIGIT.test(current)) { number += current; continue; } if (RE.POINT.test(current)) { number += current; state = FLOAT; continue; } if (RE.EXP.test(current)) { state = EXP; continue; } if (RE.SIGN.test(current) && number.length === 1 && RE.SIGN.test(number[0])) throwSyntaxError(current, i, result); } if (state === FLOAT) { if (RE.DIGIT.test(current)) { number += current; continue; } if (RE.EXP.test(current)) { state = EXP; continue; } if (RE.POINT.test(current) && number[number.length - 1] === ".") throwSyntaxError(current, i, result); } if (state === EXP) { if (RE.DIGIT.test(current)) { exponent += current; continue; } if (RE.SIGN.test(current)) { if (exponent === "") { exponent += current; continue; } if (exponent.length === 1 && RE.SIGN.test(exponent)) throwSyntaxError(current, i, result); } } if (RE.WHITESPACE.test(current)) { newNumber(); state = SEP; seenComma = false; } else if (RE.COMMA.test(current)) { newNumber(); state = SEP; seenComma = true; } else if (RE.SIGN.test(current)) { newNumber(); state = INT; number = current; } else if (RE.POINT.test(current)) { newNumber(); state = FLOAT; number = current; } else throwSyntaxError(current, i, result); } newNumber(); return result; } const units = [ "mm", "cm", "in", "pt", "pc", "px" ]; const unitConversion = { mm: { mm: 1, cm: .1, in: 1 / 25.4, pt: 72 / 25.4, pc: 6 / 25.4, px: -1 }, cm: { mm: 10, cm: 1, in: 1 / 2.54, pt: 72 / 2.54, pc: 6 / 2.54, px: -1 }, in: { mm: 25.4, cm: 2.54, in: 1, pt: 72, pc: 6, px: -1 }, pt: { mm: 25.4 / 72, cm: 2.54 / 72, in: 1 / 72, pt: 1, pc: 6 / 72, px: -1 }, pc: { mm: 25.4 / 6, cm: 2.54 / 6, in: 1 / 6, pt: 72 / 6, pc: 1, px: -1 }, px: { px: 1 } }; function parseFloatWithUnits(string) { let theUnit = "px"; if (typeof string === "string" || string instanceof String) for (let i = 0, n = units.length; i < n; i++) { const u = units[i]; if (string.endsWith(u)) { theUnit = u; string = string.substring(0, string.length - u.length); break; } } let scale = void 0; if (theUnit === "px" && scope.defaultUnit !== "px") scale = unitConversion["in"][scope.defaultUnit] / scope.defaultDPI; else { scale = unitConversion[theUnit][scope.defaultUnit]; if (scale < 0) scale = unitConversion[theUnit]["in"] * scope.defaultDPI; } return scale * parseFloat(string); } function getNodeTransform(node) { if (!(node.hasAttribute("transform") || node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y")))) return null; const transform = parseNodeTransform(node); if (transformStack.length > 0) transform.premultiply(transformStack[transformStack.length - 1]); currentTransform.copy(transform); transformStack.push(transform); return transform; } function parseNodeTransform(node) { const transform = new Matrix3(); const currentTransform2 = tempTransform0; if (node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y"))) { const tx = parseFloatWithUnits(node.getAttribute("x")); const ty = parseFloatWithUnits(node.getAttribute("y")); transform.translate(tx, ty); } if (node.hasAttribute("transform")) { const transformsTexts = node.getAttribute("transform").split(")"); for (let tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex--) { const transformText = transformsTexts[tIndex].trim(); if (transformText === "") continue; const openParPos = transformText.indexOf("("); const closeParPos = transformText.length; if (openParPos > 0 && openParPos < closeParPos) { const transformType = transformText.slice(0, openParPos); const array = parseFloats(transformText.slice(openParPos + 1)); currentTransform2.identity(); switch (transformType) { case "translate": if (array.length >= 1) { const tx = array[0]; let ty = 0; if (array.length >= 2) ty = array[1]; currentTransform2.translate(tx, ty); } break; case "rotate": if (array.length >= 1) { let angle = 0; let cx = 0; let cy = 0; angle = array[0] * Math.PI / 180; if (array.length >= 3) { cx = array[1]; cy = array[2]; } tempTransform1.makeTranslation(-cx, -cy); tempTransform2.makeRotation(angle); tempTransform3.multiplyMatrices(tempTransform2, tempTransform1); tempTransform1.makeTranslation(cx, cy); currentTransform2.multiplyMatrices(tempTransform1, tempTransform3); } break; case "scale": if (array.length >= 1) { const scaleX = array[0]; let scaleY = scaleX; if (array.length >= 2) scaleY = array[1]; currentTransform2.scale(scaleX, scaleY); } break; case "skewX": if (array.length === 1) currentTransform2.set(1, Math.tan(array[0] * Math.PI / 180), 0, 0, 1, 0, 0, 0, 1); break; case "skewY": if (array.length === 1) currentTransform2.set(1, 0, 0, Math.tan(array[0] * Math.PI / 180), 1, 0, 0, 0, 1); break; case "matrix": if (array.length === 6) currentTransform2.set(array[0], array[2], array[4], array[1], array[3], array[5], 0, 0, 1); break; } } transform.premultiply(currentTransform2); } } return transform; } function transformPath(path, m) { function transfVec2(v2) { tempV3.set(v2.x, v2.y, 1).applyMatrix3(m); v2.set(tempV3.x, tempV3.y); } function transfEllipseGeneric(curve) { const a = curve.xRadius; const b = curve.yRadius; const cosTheta = Math.cos(curve.aRotation); const sinTheta = Math.sin(curve.aRotation); const v1 = new Vector3(a * cosTheta, a * sinTheta, 0); const v2 = new Vector3(-b * sinTheta, b * cosTheta, 0); const f1 = v1.applyMatrix3(m); const f2 = v2.applyMatrix3(m); const mF = tempTransform0.set(f1.x, f2.x, 0, f1.y, f2.y, 0, 0, 0, 1); const mFInv = tempTransform1.copy(mF).invert(); const mQe = tempTransform2.copy(mFInv).transpose().multiply(mFInv).elements; const ed = eigenDecomposition(mQe[0], mQe[1], mQe[4]); const rt1sqrt = Math.sqrt(ed.rt1); const rt2sqrt = Math.sqrt(ed.rt2); curve.xRadius = 1 / rt1sqrt; curve.yRadius = 1 / rt2sqrt; curve.aRotation = Math.atan2(ed.sn, ed.cs); if (!((curve.aEndAngle - curve.aStartAngle) % (2 * Math.PI) < Number.EPSILON)) { const mDsqrt = tempTransform1.set(rt1sqrt, 0, 0, 0, rt2sqrt, 0, 0, 0, 1); const mRT = tempTransform2.set(ed.cs, ed.sn, 0, -ed.sn, ed.cs, 0, 0, 0, 1); const mDRF = mDsqrt.multiply(mRT).multiply(mF); const transformAngle = (phi) => { const { x: cosR, y: sinR } = new Vector3(Math.cos(phi), Math.sin(phi), 0).applyMatrix3(mDRF); return Math.atan2(sinR, cosR); }; curve.aStartAngle = transformAngle(curve.aStartAngle); curve.aEndAngle = transformAngle(curve.aEndAngle); if (isTransformFlipped(m)) curve.aClockwise = !curve.aClockwise; } } function transfEllipseNoSkew(curve) { const sx = getTransformScaleX(m); const sy = getTransformScaleY(m); curve.xRadius *= sx; curve.yRadius *= sy; const theta = sx > Number.EPSILON ? Math.atan2(m.elements[1], m.elements[0]) : Math.atan2(-m.elements[3], m.elements[4]); curve.aRotation += theta; if (isTransformFlipped(m)) { curve.aStartAngle *= -1; curve.aEndAngle *= -1; curve.aClockwise = !curve.aClockwise; } } const subPaths = path.subPaths; for (let i = 0, n = subPaths.length; i < n; i++) { const curves = subPaths[i].curves; for (let j = 0; j < curves.length; j++) { const curve = curves[j]; if (curve.isLineCurve) { transfVec2(curve.v1); transfVec2(curve.v2); } else if (curve.isCubicBezierCurve) { transfVec2(curve.v0); transfVec2(curve.v1); transfVec2(curve.v2); transfVec2(curve.v3); } else if (curve.isQuadraticBezierCurve) { transfVec2(curve.v0); transfVec2(curve.v1); transfVec2(curve.v2); } else if (curve.isEllipseCurve) { tempV2.set(curve.aX, curve.aY); transfVec2(tempV2); curve.aX = tempV2.x; curve.aY = tempV2.y; if (isTransformSkewed(m)) transfEllipseGeneric(curve); else transfEllipseNoSkew(curve); } } } } function isTransformFlipped(m) { const te = m.elements; return te[0] * te[4] - te[1] * te[3] < 0; } function isTransformSkewed(m) { const te = m.elements; const basisDot = te[0] * te[3] + te[1] * te[4]; if (basisDot === 0) return false; const sx = getTransformScaleX(m); const sy = getTransformScaleY(m); return Math.abs(basisDot / (sx * sy)) > Number.EPSILON; } function getTransformScaleX(m) { const te = m.elements; return Math.sqrt(te[0] * te[0] + te[1] * te[1]); } function getTransformScaleY(m) { const te = m.elements; return Math.sqrt(te[3] * te[3] + te[4] * te[4]); } function eigenDecomposition(A, B, C) { let rt1, rt2, cs, sn, t; const sm = A + C; const df = A - C; const rt = Math.sqrt(df * df + 4 * B * B); if (sm > 0) { rt1 = .5 * (sm + rt); t = 1 / rt1; rt2 = A * t * C - B * t * B; } else if (sm < 0) rt2 = .5 * (sm - rt); else { rt1 = .5 * rt; rt2 = -.5 * rt; } if (df > 0) cs = df + rt; else cs = df - rt; if (Math.abs(cs) > 2 * Math.abs(B)) { t = -2 * B / cs; sn = 1 / Math.sqrt(1 + t * t); cs = t * sn; } else if (Math.abs(B) === 0) { cs = 1; sn = 0; } else { t = -.5 * cs / B; cs = 1 / Math.sqrt(1 + t * t); sn = t * cs; } if (df > 0) { t = cs; cs = -sn; sn = t; } return { rt1, rt2, cs, sn }; } const paths = []; const stylesheets = {}; const transformStack = []; const tempTransform0 = new Matrix3(); const tempTransform1 = new Matrix3(); const tempTransform2 = new Matrix3(); const tempTransform3 = new Matrix3(); const tempV2 = new Vector2(); const tempV3 = new Vector3(); const currentTransform = new Matrix3(); const xml = new DOMParser().parseFromString(text, "image/svg+xml"); parseNode(xml.documentElement, { fill: "#000", fillOpacity: 1, strokeOpacity: 1, strokeWidth: 1, strokeLineJoin: "miter", strokeLineCap: "butt", strokeMiterLimit: 4 }); return { paths, xml: xml.documentElement }; } static createShapes(shapePath) { const BIGNUMBER = 999999999; const IntersectionLocationType = { ORIGIN: 0, DESTINATION: 1, BETWEEN: 2, LEFT: 3, RIGHT: 4, BEHIND: 5, BEYOND: 6 }; const classifyResult = { loc: IntersectionLocationType.ORIGIN, t: 0 }; function findEdgeIntersection(a0, a1, b0, b1) { const x1 = a0.x; const x2 = a1.x; const x3 = b0.x; const x4 = b1.x; const y1 = a0.y; const y2 = a1.y; const y3 = b0.y; const y4 = b1.y; const nom1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); const nom2 = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); const denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); const t1 = nom1 / denom; const t2 = nom2 / denom; if (denom === 0 && nom1 !== 0 || t1 <= 0 || t1 >= 1 || t2 < 0 || t2 > 1) return null; else if (nom1 === 0 && denom === 0) { for (let i = 0; i < 2; i++) { classifyPoint(i === 0 ? b0 : b1, a0, a1); if (classifyResult.loc == IntersectionLocationType.ORIGIN) { const point = i === 0 ? b0 : b1; return { x: point.x, y: point.y, t: classifyResult.t }; } else if (classifyResult.loc == IntersectionLocationType.BETWEEN) return { x: +(x1 + classifyResult.t * (x2 - x1)).toPrecision(10), y: +(y1 + classifyResult.t * (y2 - y1)).toPrecision(10), t: classifyResult.t }; } return null; } else { for (let i = 0; i < 2; i++) { classifyPoint(i === 0 ? b0 : b1, a0, a1); if (classifyResult.loc == IntersectionLocationType.ORIGIN) { const point = i === 0 ? b0 : b1; return { x: point.x, y: point.y, t: classifyResult.t }; } } return { x: +(x1 + t1 * (x2 - x1)).toPrecision(10), y: +(y1 + t1 * (y2 - y1)).toPrecision(10), t: t1 }; } } function classifyPoint(p, edgeStart, edgeEnd) { const ax = edgeEnd.x - edgeStart.x; const ay = edgeEnd.y - edgeStart.y; const bx = p.x - edgeStart.x; const by = p.y - edgeStart.y; const sa = ax * by - bx * ay; if (p.x === edgeStart.x && p.y === edgeStart.y) { classifyResult.loc = IntersectionLocationType.ORIGIN; classifyResult.t = 0; return; } if (p.x === edgeEnd.x && p.y === edgeEnd.y) { classifyResult.loc = IntersectionLocationType.DESTINATION; classifyResult.t = 1; return; } if (sa < -Number.EPSILON) { classifyResult.loc = IntersectionLocationType.LEFT; return; } if (sa > Number.EPSILON) { classifyResult.loc = IntersectionLocationType.RIGHT; return; } if (ax * bx < 0 || ay * by < 0) { classifyResult.loc = IntersectionLocationType.BEHIND; return; } if (Math.sqrt(ax * ax + ay * ay) < Math.sqrt(bx * bx + by * by)) { classifyResult.loc = IntersectionLocationType.BEYOND; return; } let t; if (ax !== 0) t = bx / ax; else t = by / ay; classifyResult.loc = IntersectionLocationType.BETWEEN; classifyResult.t = t; } function getIntersections(path1, path2) { const intersectionsRaw = []; const intersections = []; for (let index = 1; index < path1.length; index++) { const path1EdgeStart = path1[index - 1]; const path1EdgeEnd = path1[index]; for (let index2 = 1; index2 < path2.length; index2++) { const path2EdgeStart = path2[index2 - 1]; const path2EdgeEnd = path2[index2]; const intersection = findEdgeIntersection(path1EdgeStart, path1EdgeEnd, path2EdgeStart, path2EdgeEnd); if (intersection !== null && intersectionsRaw.find((i) => i.t <= intersection.t + Number.EPSILON && i.t >= intersection.t - Number.EPSILON) === void 0) { intersectionsRaw.push(intersection); intersections.push(new Vector2(intersection.x, intersection.y)); } } } return intersections; } function getScanlineIntersections(scanline, boundingBox, paths) { const center = new Vector2(); boundingBox.getCenter(center); const allIntersections = []; paths.forEach((path) => { if (path.boundingBox.containsPoint(center)) getIntersections(scanline, path.points).forEach((p) => { allIntersections.push({ identifier: path.identifier, isCW: path.isCW, point: p }); }); }); allIntersections.sort((i1, i2) => { return i1.point.x - i2.point.x; }); return allIntersections; } function isHoleTo(simplePath, allPaths, scanlineMinX2, scanlineMaxX2, _fillRule) { if (_fillRule === null || _fillRule === void 0 || _fillRule === "") _fillRule = "nonzero"; const centerBoundingBox = new Vector2(); simplePath.boundingBox.getCenter(centerBoundingBox); const scanlineIntersections = getScanlineIntersections([new Vector2(scanlineMinX2, centerBoundingBox.y), new Vector2(scanlineMaxX2, centerBoundingBox.y)], simplePath.boundingBox, allPaths); scanlineIntersections.sort((i1, i2) => { return i1.point.x - i2.point.x; }); const baseIntersections = []; const otherIntersections = []; scanlineIntersections.forEach((i2) => { if (i2.identifier === simplePath.identifier) baseIntersections.push(i2); else otherIntersections.push(i2); }); const firstXOfPath = baseIntersections[0].point.x; const stack = []; let i = 0; while (i < otherIntersections.length && otherIntersections[i].point.x < firstXOfPath) { if (stack.length > 0 && stack[stack.length - 1] === otherIntersections[i].identifier) stack.pop(); else stack.push(otherIntersections[i].identifier); i++; } stack.push(simplePath.identifier); if (_fillRule === "evenodd") { const isHole = stack.length % 2 === 0 ? true : false; const isHoleFor = stack[stack.length - 2]; return { identifier: simplePath.identifier, isHole, for: isHoleFor }; } else if (_fillRule === "nonzero") { let isHole = true; let isHoleFor = null; let lastCWValue = null; for (let i2 = 0; i2 < stack.length; i2++) { const identifier = stack[i2]; if (isHole) { lastCWValue = allPaths[identifier].isCW; isHole = false; isHoleFor = identifier; } else if (lastCWValue !== allPaths[identifier].isCW) { lastCWValue = allPaths[identifier].isCW; isHole = true; } } return { identifier: simplePath.identifier, isHole, for: isHoleFor }; } else console.warn("fill-rule: \"" + _fillRule + "\" is currently not implemented."); } let scanlineMinX = BIGNUMBER; let scanlineMaxX = -999999999; let simplePaths = shapePath.subPaths.map((p) => { const points = p.getPoints(); let maxY = -999999999; let minY = BIGNUMBER; let maxX = -999999999; let minX = BIGNUMBER; for (let i = 0; i < points.length; i++) { const p2 = points[i]; if (p2.y > maxY) maxY = p2.y; if (p2.y < minY) minY = p2.y; if (p2.x > maxX) maxX = p2.x; if (p2.x < minX) minX = p2.x; } if (scanlineMaxX <= maxX) scanlineMaxX = maxX + 1; if (scanlineMinX >= minX) scanlineMinX = minX - 1; return { curves: p.curves, points, isCW: ShapeUtils.isClockWise(points), identifier: -1, boundingBox: new Box2(new Vector2(minX, minY), new Vector2(maxX, maxY)) }; }); simplePaths = simplePaths.filter((sp) => sp.points.length > 1); for (let identifier = 0; identifier < simplePaths.length; identifier++) simplePaths[identifier].identifier = identifier; const isAHole = simplePaths.map((p) => isHoleTo(p, simplePaths, scanlineMinX, scanlineMaxX, shapePath.userData ? shapePath.userData.style.fillRule : void 0)); const shapesToReturn = []; simplePaths.forEach((p) => { if (!isAHole[p.identifier].isHole) { const shape = new Shape$1(); shape.curves = p.curves; isAHole.filter((h) => h.isHole && h.for === p.identifier).forEach((h) => { const hole = simplePaths[h.identifier]; const path = new Path(); path.curves = hole.curves; shape.holes.push(path); }); shapesToReturn.push(shape); } }); return shapesToReturn; } static getStrokeStyle(width, color, lineJoin, lineCap, miterLimit) { width = width !== void 0 ? width : 1; color = color !== void 0 ? color : "#000"; lineJoin = lineJoin !== void 0 ? lineJoin : "miter"; lineCap = lineCap !== void 0 ? lineCap : "butt"; miterLimit = miterLimit !== void 0 ? miterLimit : 4; return { strokeColor: color, strokeWidth: width, strokeLineJoin: lineJoin, strokeLineCap: lineCap, strokeMiterLimit: miterLimit }; } static pointsToStroke(points, style, arcDivisions, minDistance) { const vertices = []; const normals = []; const uvs = []; if (SVGLoader2.pointsToStrokeWithBuffers(points, style, arcDivisions, minDistance, vertices, normals, uvs) === 0) return null; const geometry = new BufferGeometry(); geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3)); geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3)); geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2)); return geometry; } static pointsToStrokeWithBuffers(points, style, arcDivisions, minDistance, vertices, normals, uvs, vertexOffset) { const tempV2_1 = new Vector2(); const tempV2_2 = new Vector2(); const tempV2_3 = new Vector2(); const tempV2_4 = new Vector2(); const tempV2_5 = new Vector2(); const tempV2_6 = new Vector2(); const tempV2_7 = new Vector2(); const lastPointL = new Vector2(); const lastPointR = new Vector2(); const point0L = new Vector2(); const point0R = new Vector2(); const currentPointL = new Vector2(); const currentPointR = new Vector2(); const nextPointL = new Vector2(); const nextPointR = new Vector2(); const innerPoint = new Vector2(); const outerPoint = new Vector2(); arcDivisions = arcDivisions !== void 0 ? arcDivisions : 12; minDistance = minDistance !== void 0 ? minDistance : .001; vertexOffset = vertexOffset !== void 0 ? vertexOffset : 0; points = removeDuplicatedPoints(points); const numPoints = points.length; if (numPoints < 2) return 0; const isClosed = points[0].equals(points[numPoints - 1]); let currentPoint; let previousPoint = points[0]; let nextPoint; const strokeWidth2 = style.strokeWidth / 2; const deltaU = 1 / (numPoints - 1); let u0 = 0, u1; let innerSideModified; let joinIsOnLeftSide; let isMiter; let initialJoinIsOnLeftSide = false; let numVertices = 0; let currentCoordinate = vertexOffset * 3; let currentCoordinateUV = vertexOffset * 2; getNormal(points[0], points[1], tempV2_1).multiplyScalar(strokeWidth2); lastPointL.copy(points[0]).sub(tempV2_1); lastPointR.copy(points[0]).add(tempV2_1); point0L.copy(lastPointL); point0R.copy(lastPointR); for (let iPoint = 1; iPoint < numPoints; iPoint++) { currentPoint = points[iPoint]; if (iPoint === numPoints - 1) if (isClosed) nextPoint = points[1]; else nextPoint = void 0; else nextPoint = points[iPoint + 1]; const normal1 = tempV2_1; getNormal(previousPoint, currentPoint, normal1); tempV2_3.copy(normal1).multiplyScalar(strokeWidth2); currentPointL.copy(currentPoint).sub(tempV2_3); currentPointR.copy(currentPoint).add(tempV2_3); u1 = u0 + deltaU; innerSideModified = false; if (nextPoint !== void 0) { getNormal(currentPoint, nextPoint, tempV2_2); tempV2_3.copy(tempV2_2).multiplyScalar(strokeWidth2); nextPointL.copy(currentPoint).sub(tempV2_3); nextPointR.copy(currentPoint).add(tempV2_3); joinIsOnLeftSide = true; tempV2_3.subVectors(nextPoint, previousPoint); if (normal1.dot(tempV2_3) < 0) joinIsOnLeftSide = false; if (iPoint === 1) initialJoinIsOnLeftSide = joinIsOnLeftSide; tempV2_3.subVectors(nextPoint, currentPoint); tempV2_3.normalize(); const dot = Math.abs(normal1.dot(tempV2_3)); if (dot > Number.EPSILON) { const miterSide = strokeWidth2 / dot; tempV2_3.multiplyScalar(-miterSide); tempV2_4.subVectors(currentPoint, previousPoint); tempV2_5.copy(tempV2_4).setLength(miterSide).add(tempV2_3); innerPoint.copy(tempV2_5).negate(); const miterLength2 = tempV2_5.length(); const segmentLengthPrev = tempV2_4.length(); tempV2_4.divideScalar(segmentLengthPrev); tempV2_6.subVectors(nextPoint, currentPoint); const segmentLengthNext = tempV2_6.length(); tempV2_6.divideScalar(segmentLengthNext); if (tempV2_4.dot(innerPoint) < segmentLengthPrev && tempV2_6.dot(innerPoint) < segmentLengthNext) innerSideModified = true; outerPoint.copy(tempV2_5).add(currentPoint); innerPoint.add(currentPoint); isMiter = false; if (innerSideModified) if (joinIsOnLeftSide) { nextPointR.copy(innerPoint); currentPointR.copy(innerPoint); } else { nextPointL.copy(innerPoint); currentPointL.copy(innerPoint); } else makeSegmentTriangles(); switch (style.strokeLineJoin) { case "bevel": makeSegmentWithBevelJoin(joinIsOnLeftSide, innerSideModified, u1); break; case "round": createSegmentTrianglesWithMiddleSection(joinIsOnLeftSide, innerSideModified); if (joinIsOnLeftSide) makeCircularSector(currentPoint, currentPointL, nextPointL, u1, 0); else makeCircularSector(currentPoint, nextPointR, currentPointR, u1, 1); break; default: const miterFraction = strokeWidth2 * style.strokeMiterLimit / miterLength2; if (miterFraction < 1) if (style.strokeLineJoin !== "miter-clip") { makeSegmentWithBevelJoin(joinIsOnLeftSide, innerSideModified, u1); break; } else { createSegmentTrianglesWithMiddleSection(joinIsOnLeftSide, innerSideModified); if (joinIsOnLeftSide) { tempV2_6.subVectors(outerPoint, currentPointL).multiplyScalar(miterFraction).add(currentPointL); tempV2_7.subVectors(outerPoint, nextPointL).multiplyScalar(miterFraction).add(nextPointL); addVertex(currentPointL, u1, 0); addVertex(tempV2_6, u1, 0); addVertex(currentPoint, u1, .5); addVertex(currentPoint, u1, .5); addVertex(tempV2_6, u1, 0); addVertex(tempV2_7, u1, 0); addVertex(currentPoint, u1, .5); addVertex(tempV2_7, u1, 0); addVertex(nextPointL, u1, 0); } else { tempV2_6.subVectors(outerPoint, currentPointR).multiplyScalar(miterFraction).add(currentPointR); tempV2_7.subVectors(outerPoint, nextPointR).multiplyScalar(miterFraction).add(nextPointR); addVertex(currentPointR, u1, 1); addVertex(tempV2_6, u1, 1); addVertex(currentPoint, u1, .5); addVertex(currentPoint, u1, .5); addVertex(tempV2_6, u1, 1); addVertex(tempV2_7, u1, 1); addVertex(currentPoint, u1, .5); addVertex(tempV2_7, u1, 1); addVertex(nextPointR, u1, 1); } } else { if (innerSideModified) { if (joinIsOnLeftSide) { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(outerPoint, u1, 0); addVertex(lastPointR, u0, 1); addVertex(outerPoint, u1, 0); addVertex(innerPoint, u1, 1); } else { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(outerPoint, u1, 1); addVertex(lastPointL, u0, 0); addVertex(innerPoint, u1, 0); addVertex(outerPoint, u1, 1); } if (joinIsOnLeftSide) nextPointL.copy(outerPoint); else nextPointR.copy(outerPoint); } else if (joinIsOnLeftSide) { addVertex(currentPointL, u1, 0); addVertex(outerPoint, u1, 0); addVertex(currentPoint, u1, .5); addVertex(currentPoint, u1, .5); addVertex(outerPoint, u1, 0); addVertex(nextPointL, u1, 0); } else { addVertex(currentPointR, u1, 1); addVertex(outerPoint, u1, 1); addVertex(currentPoint, u1, .5); addVertex(currentPoint, u1, .5); addVertex(outerPoint, u1, 1); addVertex(nextPointR, u1, 1); } isMiter = true; } break; } } else makeSegmentTriangles(); } else makeSegmentTriangles(); if (!isClosed && iPoint === numPoints - 1) addCapGeometry(points[0], point0L, point0R, joinIsOnLeftSide, true, u0); u0 = u1; previousPoint = currentPoint; lastPointL.copy(nextPointL); lastPointR.copy(nextPointR); } if (!isClosed) addCapGeometry(currentPoint, currentPointL, currentPointR, joinIsOnLeftSide, false, u1); else if (innerSideModified && vertices) { let lastOuter = outerPoint; let lastInner = innerPoint; if (initialJoinIsOnLeftSide !== joinIsOnLeftSide) { lastOuter = innerPoint; lastInner = outerPoint; } if (joinIsOnLeftSide) { if (isMiter || initialJoinIsOnLeftSide) { lastInner.toArray(vertices, 0); lastInner.toArray(vertices, 9); if (isMiter) lastOuter.toArray(vertices, 3); } } else if (isMiter || !initialJoinIsOnLeftSide) { lastInner.toArray(vertices, 3); lastInner.toArray(vertices, 9); if (isMiter) lastOuter.toArray(vertices, 0); } } return numVertices; function getNormal(p1, p2, result) { result.subVectors(p2, p1); return result.set(-result.y, result.x).normalize(); } function addVertex(position, u, v) { if (vertices) { vertices[currentCoordinate] = position.x; vertices[currentCoordinate + 1] = position.y; vertices[currentCoordinate + 2] = 0; if (normals) { normals[currentCoordinate] = 0; normals[currentCoordinate + 1] = 0; normals[currentCoordinate + 2] = 1; } currentCoordinate += 3; if (uvs) { uvs[currentCoordinateUV] = u; uvs[currentCoordinateUV + 1] = v; currentCoordinateUV += 2; } } numVertices += 3; } function makeCircularSector(center, p1, p2, u, v) { tempV2_1.copy(p1).sub(center).normalize(); tempV2_2.copy(p2).sub(center).normalize(); let angle = Math.PI; const dot = tempV2_1.dot(tempV2_2); if (Math.abs(dot) < 1) angle = Math.abs(Math.acos(dot)); angle /= arcDivisions; tempV2_3.copy(p1); for (let i = 0, il = arcDivisions - 1; i < il; i++) { tempV2_4.copy(tempV2_3).rotateAround(center, angle); addVertex(tempV2_3, u, v); addVertex(tempV2_4, u, v); addVertex(center, u, .5); tempV2_3.copy(tempV2_4); } addVertex(tempV2_4, u, v); addVertex(p2, u, v); addVertex(center, u, .5); } function makeSegmentTriangles() { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(currentPointL, u1, 0); addVertex(lastPointR, u0, 1); addVertex(currentPointL, u1, 0); addVertex(currentPointR, u1, 1); } function makeSegmentWithBevelJoin(joinIsOnLeftSide2, innerSideModified2, u) { if (innerSideModified2) if (joinIsOnLeftSide2) { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(currentPointL, u1, 0); addVertex(lastPointR, u0, 1); addVertex(currentPointL, u1, 0); addVertex(innerPoint, u1, 1); addVertex(currentPointL, u, 0); addVertex(nextPointL, u, 0); addVertex(innerPoint, u, .5); } else { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(currentPointR, u1, 1); addVertex(lastPointL, u0, 0); addVertex(innerPoint, u1, 0); addVertex(currentPointR, u1, 1); addVertex(currentPointR, u, 1); addVertex(innerPoint, u, 0); addVertex(nextPointR, u, 1); } else if (joinIsOnLeftSide2) { addVertex(currentPointL, u, 0); addVertex(nextPointL, u, 0); addVertex(currentPoint, u, .5); } else { addVertex(currentPointR, u, 1); addVertex(nextPointR, u, 0); addVertex(currentPoint, u, .5); } } function createSegmentTrianglesWithMiddleSection(joinIsOnLeftSide2, innerSideModified2) { if (innerSideModified2) if (joinIsOnLeftSide2) { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(currentPointL, u1, 0); addVertex(lastPointR, u0, 1); addVertex(currentPointL, u1, 0); addVertex(innerPoint, u1, 1); addVertex(currentPointL, u0, 0); addVertex(currentPoint, u1, .5); addVertex(innerPoint, u1, 1); addVertex(currentPoint, u1, .5); addVertex(nextPointL, u0, 0); addVertex(innerPoint, u1, 1); } else { addVertex(lastPointR, u0, 1); addVertex(lastPointL, u0, 0); addVertex(currentPointR, u1, 1); addVertex(lastPointL, u0, 0); addVertex(innerPoint, u1, 0); addVertex(currentPointR, u1, 1); addVertex(currentPointR, u0, 1); addVertex(innerPoint, u1, 0); addVertex(currentPoint, u1, .5); addVertex(currentPoint, u1, .5); addVertex(innerPoint, u1, 0); addVertex(nextPointR, u0, 1); } } function addCapGeometry(center, p1, p2, joinIsOnLeftSide2, start, u) { switch (style.strokeLineCap) { case "round": if (start) makeCircularSector(center, p2, p1, u, .5); else makeCircularSector(center, p1, p2, u, .5); break; case "square": if (start) { tempV2_1.subVectors(p1, center); tempV2_2.set(tempV2_1.y, -tempV2_1.x); tempV2_3.addVectors(tempV2_1, tempV2_2).add(center); tempV2_4.subVectors(tempV2_2, tempV2_1).add(center); if (joinIsOnLeftSide2) { tempV2_3.toArray(vertices, 3); tempV2_4.toArray(vertices, 0); tempV2_4.toArray(vertices, 9); } else { tempV2_3.toArray(vertices, 3); uvs[7] === 1 ? tempV2_4.toArray(vertices, 9) : tempV2_3.toArray(vertices, 9); tempV2_4.toArray(vertices, 0); } } else { tempV2_1.subVectors(p2, center); tempV2_2.set(tempV2_1.y, -tempV2_1.x); tempV2_3.addVectors(tempV2_1, tempV2_2).add(center); tempV2_4.subVectors(tempV2_2, tempV2_1).add(center); const vl = vertices.length; if (joinIsOnLeftSide2) { tempV2_3.toArray(vertices, vl - 3); tempV2_4.toArray(vertices, vl - 6); tempV2_4.toArray(vertices, vl - 12); } else { tempV2_4.toArray(vertices, vl - 6); tempV2_3.toArray(vertices, vl - 3); tempV2_4.toArray(vertices, vl - 12); } } break; } } function removeDuplicatedPoints(points2) { let dupPoints = false; for (let i = 1, n = points2.length - 1; i < n; i++) if (points2[i].distanceTo(points2[i + 1]) < minDistance) { dupPoints = true; break; } if (!dupPoints) return points2; const newPoints = []; newPoints.push(points2[0]); for (let i = 1, n = points2.length - 1; i < n; i++) if (points2[i].distanceTo(points2[i + 1]) >= minDistance) newPoints.push(points2[i]); newPoints.push(points2[points2.length - 1]); return newPoints; } } } return SVGLoader2; })(); //#endregion //#region node_modules/three-stdlib/loaders/DRACOLoader.js var _taskCache = /* @__PURE__ */ new WeakMap(); var DRACOLoader = class extends Loader$1 { constructor(manager) { super(manager); this.decoderPath = ""; this.decoderConfig = {}; this.decoderBinary = null; this.decoderPending = null; this.workerLimit = 4; this.workerPool = []; this.workerNextTaskID = 1; this.workerSourceURL = ""; this.defaultAttributeIDs = { position: "POSITION", normal: "NORMAL", color: "COLOR", uv: "TEX_COORD" }; this.defaultAttributeTypes = { position: "Float32Array", normal: "Float32Array", color: "Float32Array", uv: "Float32Array" }; } setDecoderPath(path) { this.decoderPath = path; return this; } setDecoderConfig(config) { this.decoderConfig = config; return this; } setWorkerLimit(workerLimit) { this.workerLimit = workerLimit; return this; } load(url, onLoad, onProgress, onError) { const loader = new FileLoader(this.manager); loader.setPath(this.path); loader.setResponseType("arraybuffer"); loader.setRequestHeader(this.requestHeader); loader.setWithCredentials(this.withCredentials); loader.load(url, (buffer) => { const taskConfig = { attributeIDs: this.defaultAttributeIDs, attributeTypes: this.defaultAttributeTypes, useUniqueIDs: false }; this.decodeGeometry(buffer, taskConfig).then(onLoad).catch(onError); }, onProgress, onError); } /** @deprecated Kept for backward-compatibility with previous DRACOLoader versions. */ decodeDracoFile(buffer, callback, attributeIDs, attributeTypes) { const taskConfig = { attributeIDs: attributeIDs || this.defaultAttributeIDs, attributeTypes: attributeTypes || this.defaultAttributeTypes, useUniqueIDs: !!attributeIDs }; this.decodeGeometry(buffer, taskConfig).then(callback); } decodeGeometry(buffer, taskConfig) { for (const attribute in taskConfig.attributeTypes) { const type = taskConfig.attributeTypes[attribute]; if (type.BYTES_PER_ELEMENT !== void 0) taskConfig.attributeTypes[attribute] = type.name; } const taskKey = JSON.stringify(taskConfig); if (_taskCache.has(buffer)) { const cachedTask = _taskCache.get(buffer); if (cachedTask.key === taskKey) return cachedTask.promise; else if (buffer.byteLength === 0) throw new Error("THREE.DRACOLoader: Unable to re-decode a buffer with different settings. Buffer has already been transferred."); } let worker; const taskID = this.workerNextTaskID++; const taskCost = buffer.byteLength; const geometryPending = this._getWorker(taskID, taskCost).then((_worker) => { worker = _worker; return new Promise((resolve, reject) => { worker._callbacks[taskID] = { resolve, reject }; worker.postMessage({ type: "decode", id: taskID, taskConfig, buffer }, [buffer]); }); }).then((message) => this._createGeometry(message.geometry)); geometryPending.catch(() => true).then(() => { if (worker && taskID) this._releaseTask(worker, taskID); }); _taskCache.set(buffer, { key: taskKey, promise: geometryPending }); return geometryPending; } _createGeometry(geometryData) { const geometry = new BufferGeometry(); if (geometryData.index) geometry.setIndex(new BufferAttribute(geometryData.index.array, 1)); for (let i = 0; i < geometryData.attributes.length; i++) { const attribute = geometryData.attributes[i]; const name = attribute.name; const array = attribute.array; const itemSize = attribute.itemSize; geometry.setAttribute(name, new BufferAttribute(array, itemSize)); } return geometry; } _loadLibrary(url, responseType) { const loader = new FileLoader(this.manager); loader.setPath(this.decoderPath); loader.setResponseType(responseType); loader.setWithCredentials(this.withCredentials); return new Promise((resolve, reject) => { loader.load(url, resolve, void 0, reject); }); } preload() { this._initDecoder(); return this; } _initDecoder() { if (this.decoderPending) return this.decoderPending; const useJS = typeof WebAssembly !== "object" || this.decoderConfig.type === "js"; const librariesPending = []; if (useJS) librariesPending.push(this._loadLibrary("draco_decoder.js", "text")); else { librariesPending.push(this._loadLibrary("draco_wasm_wrapper.js", "text")); librariesPending.push(this._loadLibrary("draco_decoder.wasm", "arraybuffer")); } this.decoderPending = Promise.all(librariesPending).then((libraries) => { const jsContent = libraries[0]; if (!useJS) this.decoderConfig.wasmBinary = libraries[1]; const fn = DRACOWorker.toString(); const body = [ "/* draco decoder */", jsContent, "", "/* worker */", fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")) ].join("\n"); this.workerSourceURL = URL.createObjectURL(new Blob([body])); }); return this.decoderPending; } _getWorker(taskID, taskCost) { return this._initDecoder().then(() => { if (this.workerPool.length < this.workerLimit) { const worker2 = new Worker(this.workerSourceURL); worker2._callbacks = {}; worker2._taskCosts = {}; worker2._taskLoad = 0; worker2.postMessage({ type: "init", decoderConfig: this.decoderConfig }); worker2.onmessage = function(e) { const message = e.data; switch (message.type) { case "decode": worker2._callbacks[message.id].resolve(message); break; case "error": worker2._callbacks[message.id].reject(message); break; default: console.error("THREE.DRACOLoader: Unexpected message, \"" + message.type + "\""); } }; this.workerPool.push(worker2); } else this.workerPool.sort(function(a, b) { return a._taskLoad > b._taskLoad ? -1 : 1; }); const worker = this.workerPool[this.workerPool.length - 1]; worker._taskCosts[taskID] = taskCost; worker._taskLoad += taskCost; return worker; }); } _releaseTask(worker, taskID) { worker._taskLoad -= worker._taskCosts[taskID]; delete worker._callbacks[taskID]; delete worker._taskCosts[taskID]; } debug() { console.log("Task load: ", this.workerPool.map((worker) => worker._taskLoad)); } dispose() { for (let i = 0; i < this.workerPool.length; ++i) this.workerPool[i].terminate(); this.workerPool.length = 0; return this; } }; function DRACOWorker() { let decoderConfig; let decoderPending; onmessage = function(e) { const message = e.data; switch (message.type) { case "init": decoderConfig = message.decoderConfig; decoderPending = new Promise(function(resolve) { decoderConfig.onModuleLoaded = function(draco) { resolve({ draco }); }; DracoDecoderModule(decoderConfig); }); break; case "decode": const buffer = message.buffer; const taskConfig = message.taskConfig; decoderPending.then((module) => { const draco = module.draco; const decoder = new draco.Decoder(); const decoderBuffer = new draco.DecoderBuffer(); decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength); try { const geometry = decodeGeometry(draco, decoder, decoderBuffer, taskConfig); const buffers = geometry.attributes.map((attr) => attr.array.buffer); if (geometry.index) buffers.push(geometry.index.array.buffer); self.postMessage({ type: "decode", id: message.id, geometry }, buffers); } catch (error) { console.error(error); self.postMessage({ type: "error", id: message.id, error: error.message }); } finally { draco.destroy(decoderBuffer); draco.destroy(decoder); } }); break; } }; function decodeGeometry(draco, decoder, decoderBuffer, taskConfig) { const attributeIDs = taskConfig.attributeIDs; const attributeTypes = taskConfig.attributeTypes; let dracoGeometry; let decodingStatus; const geometryType = decoder.GetEncodedGeometryType(decoderBuffer); if (geometryType === draco.TRIANGULAR_MESH) { dracoGeometry = new draco.Mesh(); decodingStatus = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry); } else if (geometryType === draco.POINT_CLOUD) { dracoGeometry = new draco.PointCloud(); decodingStatus = decoder.DecodeBufferToPointCloud(decoderBuffer, dracoGeometry); } else throw new Error("THREE.DRACOLoader: Unexpected geometry type."); if (!decodingStatus.ok() || dracoGeometry.ptr === 0) throw new Error("THREE.DRACOLoader: Decoding failed: " + decodingStatus.error_msg()); const geometry = { index: null, attributes: [] }; for (const attributeName in attributeIDs) { const attributeType = self[attributeTypes[attributeName]]; let attribute; let attributeID; if (taskConfig.useUniqueIDs) { attributeID = attributeIDs[attributeName]; attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeID); } else { attributeID = decoder.GetAttributeId(dracoGeometry, draco[attributeIDs[attributeName]]); if (attributeID === -1) continue; attribute = decoder.GetAttribute(dracoGeometry, attributeID); } geometry.attributes.push(decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute)); } if (geometryType === draco.TRIANGULAR_MESH) geometry.index = decodeIndex(draco, decoder, dracoGeometry); draco.destroy(dracoGeometry); return geometry; } function decodeIndex(draco, decoder, dracoGeometry) { const numIndices = dracoGeometry.num_faces() * 3; const byteLength = numIndices * 4; const ptr = draco._malloc(byteLength); decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); const index = new Uint32Array(draco.HEAPF32.buffer, ptr, numIndices).slice(); draco._free(ptr); return { array: index, itemSize: 1 }; } function decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute) { const numComponents = attribute.num_components(); const numValues = dracoGeometry.num_points() * numComponents; const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; const dataType = getDracoDataType(draco, attributeType); const ptr = draco._malloc(byteLength); decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr); const array = new attributeType(draco.HEAPF32.buffer, ptr, numValues).slice(); draco._free(ptr); return { name: attributeName, array, itemSize: numComponents }; } function getDracoDataType(draco, attributeType) { switch (attributeType) { case Float32Array: return draco.DT_FLOAT32; case Int8Array: return draco.DT_INT8; case Int16Array: return draco.DT_INT16; case Int32Array: return draco.DT_INT32; case Uint8Array: return draco.DT_UINT8; case Uint16Array: return draco.DT_UINT16; case Uint32Array: return draco.DT_UINT32; } } } //#endregion //#region node_modules/three-stdlib/lines/LineSegmentsGeometry.js var _box$1 = /* @__PURE__ */ new Box3(); var _vector = /* @__PURE__ */ new Vector3(); var LineSegmentsGeometry = class extends InstancedBufferGeometry { constructor() { super(); this.isLineSegmentsGeometry = true; this.type = "LineSegmentsGeometry"; const positions = [ -1, 2, 0, 1, 2, 0, -1, 1, 0, 1, 1, 0, -1, 0, 0, 1, 0, 0, -1, -1, 0, 1, -1, 0 ]; const uvs = [ -1, 2, 1, 2, -1, 1, 1, 1, -1, -1, 1, -1, -1, -2, 1, -2 ]; this.setIndex([ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ]); this.setAttribute("position", new Float32BufferAttribute(positions, 3)); this.setAttribute("uv", new Float32BufferAttribute(uvs, 2)); } applyMatrix4(matrix) { const start = this.attributes.instanceStart; const end = this.attributes.instanceEnd; if (start !== void 0) { start.applyMatrix4(matrix); end.applyMatrix4(matrix); start.needsUpdate = true; } if (this.boundingBox !== null) this.computeBoundingBox(); if (this.boundingSphere !== null) this.computeBoundingSphere(); return this; } setPositions(array) { let lineSegments; if (array instanceof Float32Array) lineSegments = array; else if (Array.isArray(array)) lineSegments = new Float32Array(array); const instanceBuffer = new InstancedInterleavedBuffer(lineSegments, 6, 1); this.setAttribute("instanceStart", new InterleavedBufferAttribute(instanceBuffer, 3, 0)); this.setAttribute("instanceEnd", new InterleavedBufferAttribute(instanceBuffer, 3, 3)); this.computeBoundingBox(); this.computeBoundingSphere(); return this; } setColors(array, itemSize = 3) { let colors; if (array instanceof Float32Array) colors = array; else if (Array.isArray(array)) colors = new Float32Array(array); const instanceColorBuffer = new InstancedInterleavedBuffer(colors, itemSize * 2, 1); this.setAttribute("instanceColorStart", new InterleavedBufferAttribute(instanceColorBuffer, itemSize, 0)); this.setAttribute("instanceColorEnd", new InterleavedBufferAttribute(instanceColorBuffer, itemSize, itemSize)); return this; } fromWireframeGeometry(geometry) { this.setPositions(geometry.attributes.position.array); return this; } fromEdgesGeometry(geometry) { this.setPositions(geometry.attributes.position.array); return this; } fromMesh(mesh) { this.fromWireframeGeometry(new WireframeGeometry(mesh.geometry)); return this; } fromLineSegments(lineSegments) { const geometry = lineSegments.geometry; this.setPositions(geometry.attributes.position.array); return this; } computeBoundingBox() { if (this.boundingBox === null) this.boundingBox = new Box3(); const start = this.attributes.instanceStart; const end = this.attributes.instanceEnd; if (start !== void 0 && end !== void 0) { this.boundingBox.setFromBufferAttribute(start); _box$1.setFromBufferAttribute(end); this.boundingBox.union(_box$1); } } computeBoundingSphere() { if (this.boundingSphere === null) this.boundingSphere = new Sphere$1(); if (this.boundingBox === null) this.computeBoundingBox(); const start = this.attributes.instanceStart; const end = this.attributes.instanceEnd; if (start !== void 0 && end !== void 0) { const center = this.boundingSphere.center; this.boundingBox.getCenter(center); let maxRadiusSq = 0; for (let i = 0, il = start.count; i < il; i++) { _vector.fromBufferAttribute(start, i); maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector)); _vector.fromBufferAttribute(end, i); maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector)); } this.boundingSphere.radius = Math.sqrt(maxRadiusSq); if (isNaN(this.boundingSphere.radius)) console.error("THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.", this); } } toJSON() {} applyMatrix(matrix) { console.warn("THREE.LineSegmentsGeometry: applyMatrix() has been renamed to applyMatrix4()."); return this.applyMatrix4(matrix); } }; //#endregion //#region node_modules/three-stdlib/lines/LineGeometry.js var LineGeometry = class extends LineSegmentsGeometry { constructor() { super(); this.isLineGeometry = true; this.type = "LineGeometry"; } setPositions(array) { const length = array.length - 3; const points = new Float32Array(2 * length); for (let i = 0; i < length; i += 3) { points[2 * i] = array[i]; points[2 * i + 1] = array[i + 1]; points[2 * i + 2] = array[i + 2]; points[2 * i + 3] = array[i + 3]; points[2 * i + 4] = array[i + 4]; points[2 * i + 5] = array[i + 5]; } super.setPositions(points); return this; } setColors(array, itemSize = 3) { const length = array.length - itemSize; const colors = new Float32Array(2 * length); if (itemSize === 3) for (let i = 0; i < length; i += itemSize) { colors[2 * i] = array[i]; colors[2 * i + 1] = array[i + 1]; colors[2 * i + 2] = array[i + 2]; colors[2 * i + 3] = array[i + 3]; colors[2 * i + 4] = array[i + 4]; colors[2 * i + 5] = array[i + 5]; } else for (let i = 0; i < length; i += itemSize) { colors[2 * i] = array[i]; colors[2 * i + 1] = array[i + 1]; colors[2 * i + 2] = array[i + 2]; colors[2 * i + 3] = array[i + 3]; colors[2 * i + 4] = array[i + 4]; colors[2 * i + 5] = array[i + 5]; colors[2 * i + 6] = array[i + 6]; colors[2 * i + 7] = array[i + 7]; } super.setColors(colors, itemSize); return this; } fromLine(line) { const geometry = line.geometry; this.setPositions(geometry.attributes.position.array); return this; } }; //#endregion //#region node_modules/three-stdlib/lines/LineMaterial.js var LineMaterial = class extends ShaderMaterial { constructor(parameters) { super({ type: "LineMaterial", uniforms: UniformsUtils.clone(UniformsUtils.merge([ UniformsLib.common, UniformsLib.fog, { worldUnits: { value: 1 }, linewidth: { value: 1 }, resolution: { value: new Vector2(1, 1) }, dashOffset: { value: 0 }, dashScale: { value: 1 }, dashSize: { value: 1 }, gapSize: { value: 1 } } ])), vertexShader: ` #include #include #include #include uniform float linewidth; uniform vec2 resolution; attribute vec3 instanceStart; attribute vec3 instanceEnd; #ifdef USE_COLOR #ifdef USE_LINE_COLOR_ALPHA varying vec4 vLineColor; attribute vec4 instanceColorStart; attribute vec4 instanceColorEnd; #else varying vec3 vLineColor; attribute vec3 instanceColorStart; attribute vec3 instanceColorEnd; #endif #endif #ifdef WORLD_UNITS varying vec4 worldPos; varying vec3 worldStart; varying vec3 worldEnd; #ifdef USE_DASH varying vec2 vUv; #endif #else varying vec2 vUv; #endif #ifdef USE_DASH uniform float dashScale; attribute float instanceDistanceStart; attribute float instanceDistanceEnd; varying float vLineDistance; #endif void trimSegment( const in vec4 start, inout vec4 end ) { // trim end segment so it terminates between the camera plane and the near plane // conservative estimate of the near plane float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column float nearEstimate = - 0.5 * b / a; float alpha = ( nearEstimate - start.z ) / ( end.z - start.z ); end.xyz = mix( start.xyz, end.xyz, alpha ); } void main() { #ifdef USE_COLOR vLineColor = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd; #endif #ifdef USE_DASH vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd; vUv = uv; #endif float aspect = resolution.x / resolution.y; // camera space vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 ); vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 ); #ifdef WORLD_UNITS worldStart = start.xyz; worldEnd = end.xyz; #else vUv = uv; #endif // special case for perspective projection, and segments that terminate either in, or behind, the camera plane // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space // but we need to perform ndc-space calculations in the shader, so we must address this issue directly // perhaps there is a more elegant solution -- WestLangley bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column if ( perspective ) { if ( start.z < 0.0 && end.z >= 0.0 ) { trimSegment( start, end ); } else if ( end.z < 0.0 && start.z >= 0.0 ) { trimSegment( end, start ); } } // clip space vec4 clipStart = projectionMatrix * start; vec4 clipEnd = projectionMatrix * end; // ndc space vec3 ndcStart = clipStart.xyz / clipStart.w; vec3 ndcEnd = clipEnd.xyz / clipEnd.w; // direction vec2 dir = ndcEnd.xy - ndcStart.xy; // account for clip-space aspect ratio dir.x *= aspect; dir = normalize( dir ); #ifdef WORLD_UNITS // get the offset direction as perpendicular to the view vector vec3 worldDir = normalize( end.xyz - start.xyz ); vec3 offset; if ( position.y < 0.5 ) { offset = normalize( cross( start.xyz, worldDir ) ); } else { offset = normalize( cross( end.xyz, worldDir ) ); } // sign flip if ( position.x < 0.0 ) offset *= - 1.0; float forwardOffset = dot( worldDir, vec3( 0.0, 0.0, 1.0 ) ); // don't extend the line if we're rendering dashes because we // won't be rendering the endcaps #ifndef USE_DASH // extend the line bounds to encompass endcaps start.xyz += - worldDir * linewidth * 0.5; end.xyz += worldDir * linewidth * 0.5; // shift the position of the quad so it hugs the forward edge of the line offset.xy -= dir * forwardOffset; offset.z += 0.5; #endif // endcaps if ( position.y > 1.0 || position.y < 0.0 ) { offset.xy += dir * 2.0 * forwardOffset; } // adjust for linewidth offset *= linewidth * 0.5; // set the world position worldPos = ( position.y < 0.5 ) ? start : end; worldPos.xyz += offset; // project the worldpos vec4 clip = projectionMatrix * worldPos; // shift the depth of the projected points so the line // segments overlap neatly vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd; clip.z = clipPose.z * clip.w; #else vec2 offset = vec2( dir.y, - dir.x ); // undo aspect ratio adjustment dir.x /= aspect; offset.x /= aspect; // sign flip if ( position.x < 0.0 ) offset *= - 1.0; // endcaps if ( position.y < 0.0 ) { offset += - dir; } else if ( position.y > 1.0 ) { offset += dir; } // adjust for linewidth offset *= linewidth; // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... offset /= resolution.y; // select end vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd; // back to clip space offset *= clip.w; clip.xy += offset; #endif gl_Position = clip; vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation #include #include #include } `, fragmentShader: ` uniform vec3 diffuse; uniform float opacity; uniform float linewidth; #ifdef USE_DASH uniform float dashOffset; uniform float dashSize; uniform float gapSize; #endif varying float vLineDistance; #ifdef WORLD_UNITS varying vec4 worldPos; varying vec3 worldStart; varying vec3 worldEnd; #ifdef USE_DASH varying vec2 vUv; #endif #else varying vec2 vUv; #endif #include #include #include #include #ifdef USE_COLOR #ifdef USE_LINE_COLOR_ALPHA varying vec4 vLineColor; #else varying vec3 vLineColor; #endif #endif vec2 closestLineToLine(vec3 p1, vec3 p2, vec3 p3, vec3 p4) { float mua; float mub; vec3 p13 = p1 - p3; vec3 p43 = p4 - p3; vec3 p21 = p2 - p1; float d1343 = dot( p13, p43 ); float d4321 = dot( p43, p21 ); float d1321 = dot( p13, p21 ); float d4343 = dot( p43, p43 ); float d2121 = dot( p21, p21 ); float denom = d2121 * d4343 - d4321 * d4321; float numer = d1343 * d4321 - d1321 * d4343; mua = numer / denom; mua = clamp( mua, 0.0, 1.0 ); mub = ( d1343 + d4321 * ( mua ) ) / d4343; mub = clamp( mub, 0.0, 1.0 ); return vec2( mua, mub ); } void main() { #include #ifdef USE_DASH if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps if ( mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize ) discard; // todo - FIX #endif float alpha = opacity; #ifdef WORLD_UNITS // Find the closest points on the view ray and the line segment vec3 rayEnd = normalize( worldPos.xyz ) * 1e5; vec3 lineDir = worldEnd - worldStart; vec2 params = closestLineToLine( worldStart, worldEnd, vec3( 0.0, 0.0, 0.0 ), rayEnd ); vec3 p1 = worldStart + lineDir * params.x; vec3 p2 = rayEnd * params.y; vec3 delta = p1 - p2; float len = length( delta ); float norm = len / linewidth; #ifndef USE_DASH #ifdef USE_ALPHA_TO_COVERAGE float dnorm = fwidth( norm ); alpha = 1.0 - smoothstep( 0.5 - dnorm, 0.5 + dnorm, norm ); #else if ( norm > 0.5 ) { discard; } #endif #endif #else #ifdef USE_ALPHA_TO_COVERAGE // artifacts appear on some hardware if a derivative is taken within a conditional float a = vUv.x; float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0; float len2 = a * a + b * b; float dlen = fwidth( len2 ); if ( abs( vUv.y ) > 1.0 ) { alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 ); } #else if ( abs( vUv.y ) > 1.0 ) { float a = vUv.x; float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0; float len2 = a * a + b * b; if ( len2 > 1.0 ) discard; } #endif #endif vec4 diffuseColor = vec4( diffuse, alpha ); #ifdef USE_COLOR #ifdef USE_LINE_COLOR_ALPHA diffuseColor *= vLineColor; #else diffuseColor.rgb *= vLineColor; #endif #endif #include gl_FragColor = diffuseColor; #include #include <${version$2 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> #include #include } `, clipping: true }); this.isLineMaterial = true; this.onBeforeCompile = function() { if (this.transparent) this.defines.USE_LINE_COLOR_ALPHA = "1"; else delete this.defines.USE_LINE_COLOR_ALPHA; }; Object.defineProperties(this, { color: { enumerable: true, get: function() { return this.uniforms.diffuse.value; }, set: function(value) { this.uniforms.diffuse.value = value; } }, worldUnits: { enumerable: true, get: function() { return "WORLD_UNITS" in this.defines; }, set: function(value) { if (value === true) this.defines.WORLD_UNITS = ""; else delete this.defines.WORLD_UNITS; } }, linewidth: { enumerable: true, get: function() { return this.uniforms.linewidth.value; }, set: function(value) { this.uniforms.linewidth.value = value; } }, dashed: { enumerable: true, get: function() { return Boolean("USE_DASH" in this.defines); }, set(value) { if (Boolean(value) !== Boolean("USE_DASH" in this.defines)) this.needsUpdate = true; if (value === true) this.defines.USE_DASH = ""; else delete this.defines.USE_DASH; } }, dashScale: { enumerable: true, get: function() { return this.uniforms.dashScale.value; }, set: function(value) { this.uniforms.dashScale.value = value; } }, dashSize: { enumerable: true, get: function() { return this.uniforms.dashSize.value; }, set: function(value) { this.uniforms.dashSize.value = value; } }, dashOffset: { enumerable: true, get: function() { return this.uniforms.dashOffset.value; }, set: function(value) { this.uniforms.dashOffset.value = value; } }, gapSize: { enumerable: true, get: function() { return this.uniforms.gapSize.value; }, set: function(value) { this.uniforms.gapSize.value = value; } }, opacity: { enumerable: true, get: function() { return this.uniforms.opacity.value; }, set: function(value) { this.uniforms.opacity.value = value; } }, resolution: { enumerable: true, get: function() { return this.uniforms.resolution.value; }, set: function(value) { this.uniforms.resolution.value.copy(value); } }, alphaToCoverage: { enumerable: true, get: function() { return Boolean("USE_ALPHA_TO_COVERAGE" in this.defines); }, set: function(value) { if (Boolean(value) !== Boolean("USE_ALPHA_TO_COVERAGE" in this.defines)) this.needsUpdate = true; if (value === true) { this.defines.USE_ALPHA_TO_COVERAGE = ""; this.extensions.derivatives = true; } else { delete this.defines.USE_ALPHA_TO_COVERAGE; this.extensions.derivatives = false; } } } }); this.setValues(parameters); } }; //#endregion //#region node_modules/three-stdlib/lines/LineSegments2.js var _viewport = /* @__PURE__ */ new Vector4(); var _start = /* @__PURE__ */ new Vector3(); var _end = /* @__PURE__ */ new Vector3(); var _start4 = /* @__PURE__ */ new Vector4(); var _end4 = /* @__PURE__ */ new Vector4(); var _ssOrigin = /* @__PURE__ */ new Vector4(); var _ssOrigin3 = /* @__PURE__ */ new Vector3(); var _mvMatrix = /* @__PURE__ */ new Matrix4(); var _line = /* @__PURE__ */ new Line3(); var _closestPoint = /* @__PURE__ */ new Vector3(); var _box = /* @__PURE__ */ new Box3(); var _sphere$3 = /* @__PURE__ */ new Sphere$1(); var _clipToWorldVector = /* @__PURE__ */ new Vector4(); var _ray$2, _lineWidth; function getWorldSpaceHalfWidth(camera, distance, resolution) { _clipToWorldVector.set(0, 0, -distance, 1).applyMatrix4(camera.projectionMatrix); _clipToWorldVector.multiplyScalar(1 / _clipToWorldVector.w); _clipToWorldVector.x = _lineWidth / resolution.width; _clipToWorldVector.y = _lineWidth / resolution.height; _clipToWorldVector.applyMatrix4(camera.projectionMatrixInverse); _clipToWorldVector.multiplyScalar(1 / _clipToWorldVector.w); return Math.abs(Math.max(_clipToWorldVector.x, _clipToWorldVector.y)); } function raycastWorldUnits(lineSegments, intersects) { const matrixWorld = lineSegments.matrixWorld; const geometry = lineSegments.geometry; const instanceStart = geometry.attributes.instanceStart; const instanceEnd = geometry.attributes.instanceEnd; const segmentCount = Math.min(geometry.instanceCount, instanceStart.count); for (let i = 0, l = segmentCount; i < l; i++) { _line.start.fromBufferAttribute(instanceStart, i); _line.end.fromBufferAttribute(instanceEnd, i); _line.applyMatrix4(matrixWorld); const pointOnLine = new Vector3(); const point = new Vector3(); _ray$2.distanceSqToSegment(_line.start, _line.end, point, pointOnLine); if (point.distanceTo(pointOnLine) < _lineWidth * .5) intersects.push({ point, pointOnLine, distance: _ray$2.origin.distanceTo(point), object: lineSegments, face: null, faceIndex: i, uv: null, [UV1]: null }); } } function raycastScreenSpace(lineSegments, camera, intersects) { const projectionMatrix = camera.projectionMatrix; const resolution = lineSegments.material.resolution; const matrixWorld = lineSegments.matrixWorld; const geometry = lineSegments.geometry; const instanceStart = geometry.attributes.instanceStart; const instanceEnd = geometry.attributes.instanceEnd; const segmentCount = Math.min(geometry.instanceCount, instanceStart.count); const near = -camera.near; _ray$2.at(1, _ssOrigin); _ssOrigin.w = 1; _ssOrigin.applyMatrix4(camera.matrixWorldInverse); _ssOrigin.applyMatrix4(projectionMatrix); _ssOrigin.multiplyScalar(1 / _ssOrigin.w); _ssOrigin.x *= resolution.x / 2; _ssOrigin.y *= resolution.y / 2; _ssOrigin.z = 0; _ssOrigin3.copy(_ssOrigin); _mvMatrix.multiplyMatrices(camera.matrixWorldInverse, matrixWorld); for (let i = 0, l = segmentCount; i < l; i++) { _start4.fromBufferAttribute(instanceStart, i); _end4.fromBufferAttribute(instanceEnd, i); _start4.w = 1; _end4.w = 1; _start4.applyMatrix4(_mvMatrix); _end4.applyMatrix4(_mvMatrix); if (_start4.z > near && _end4.z > near) continue; if (_start4.z > near) { const deltaDist = _start4.z - _end4.z; const t = (_start4.z - near) / deltaDist; _start4.lerp(_end4, t); } else if (_end4.z > near) { const deltaDist = _end4.z - _start4.z; const t = (_end4.z - near) / deltaDist; _end4.lerp(_start4, t); } _start4.applyMatrix4(projectionMatrix); _end4.applyMatrix4(projectionMatrix); _start4.multiplyScalar(1 / _start4.w); _end4.multiplyScalar(1 / _end4.w); _start4.x *= resolution.x / 2; _start4.y *= resolution.y / 2; _end4.x *= resolution.x / 2; _end4.y *= resolution.y / 2; _line.start.copy(_start4); _line.start.z = 0; _line.end.copy(_end4); _line.end.z = 0; const param = _line.closestPointToPointParameter(_ssOrigin3, true); _line.at(param, _closestPoint); const zPos = MathUtils.lerp(_start4.z, _end4.z, param); const isInClipSpace = zPos >= -1 && zPos <= 1; const isInside = _ssOrigin3.distanceTo(_closestPoint) < _lineWidth * .5; if (isInClipSpace && isInside) { _line.start.fromBufferAttribute(instanceStart, i); _line.end.fromBufferAttribute(instanceEnd, i); _line.start.applyMatrix4(matrixWorld); _line.end.applyMatrix4(matrixWorld); const pointOnLine = new Vector3(); const point = new Vector3(); _ray$2.distanceSqToSegment(_line.start, _line.end, point, pointOnLine); intersects.push({ point, pointOnLine, distance: _ray$2.origin.distanceTo(point), object: lineSegments, face: null, faceIndex: i, uv: null, [UV1]: null }); } } } var LineSegments2 = class extends Mesh { constructor(geometry = new LineSegmentsGeometry(), material = new LineMaterial({ color: Math.random() * 16777215 })) { super(geometry, material); this.isLineSegments2 = true; this.type = "LineSegments2"; } computeLineDistances() { const geometry = this.geometry; const instanceStart = geometry.attributes.instanceStart; const instanceEnd = geometry.attributes.instanceEnd; const lineDistances = new Float32Array(2 * instanceStart.count); for (let i = 0, j = 0, l = instanceStart.count; i < l; i++, j += 2) { _start.fromBufferAttribute(instanceStart, i); _end.fromBufferAttribute(instanceEnd, i); lineDistances[j] = j === 0 ? 0 : lineDistances[j - 1]; lineDistances[j + 1] = lineDistances[j] + _start.distanceTo(_end); } const instanceDistanceBuffer = new InstancedInterleavedBuffer(lineDistances, 2, 1); geometry.setAttribute("instanceDistanceStart", new InterleavedBufferAttribute(instanceDistanceBuffer, 1, 0)); geometry.setAttribute("instanceDistanceEnd", new InterleavedBufferAttribute(instanceDistanceBuffer, 1, 1)); return this; } raycast(raycaster, intersects) { const worldUnits = this.material.worldUnits; const camera = raycaster.camera; if (camera === null && !worldUnits) console.error("LineSegments2: \"Raycaster.camera\" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false."); const threshold = raycaster.params.Line2 !== void 0 ? raycaster.params.Line2.threshold || 0 : 0; _ray$2 = raycaster.ray; const matrixWorld = this.matrixWorld; const geometry = this.geometry; const material = this.material; _lineWidth = material.linewidth + threshold; if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); _sphere$3.copy(geometry.boundingSphere).applyMatrix4(matrixWorld); let sphereMargin; if (worldUnits) sphereMargin = _lineWidth * .5; else sphereMargin = getWorldSpaceHalfWidth(camera, Math.max(camera.near, _sphere$3.distanceToPoint(_ray$2.origin)), material.resolution); _sphere$3.radius += sphereMargin; if (_ray$2.intersectsSphere(_sphere$3) === false) return; if (geometry.boundingBox === null) geometry.computeBoundingBox(); _box.copy(geometry.boundingBox).applyMatrix4(matrixWorld); let boxMargin; if (worldUnits) boxMargin = _lineWidth * .5; else boxMargin = getWorldSpaceHalfWidth(camera, Math.max(camera.near, _box.distanceToPoint(_ray$2.origin)), material.resolution); _box.expandByScalar(boxMargin); if (_ray$2.intersectsBox(_box) === false) return; if (worldUnits) raycastWorldUnits(this, intersects); else raycastScreenSpace(this, camera, intersects); } onBeforeRender(renderer) { const uniforms = this.material.uniforms; if (uniforms && uniforms.resolution) { renderer.getViewport(_viewport); this.material.uniforms.resolution.value.set(_viewport.z, _viewport.w); } } }; //#endregion //#region node_modules/three-stdlib/lines/Line2.js var Line2 = class extends LineSegments2 { constructor(geometry = new LineGeometry(), material = new LineMaterial({ color: Math.random() * 16777215 })) { super(geometry, material); this.isLine2 = true; this.type = "Line2"; } }; //#endregion //#region node_modules/three-stdlib/libs/MeshoptDecoder.js var generated; var MeshoptDecoder = () => { if (generated) return generated; const wasm_base = "B9h9z9tFBBBF8fL9gBB9gLaaaaaFa9gEaaaB9gFaFa9gEaaaFaEMcBFFFGGGEIIILF9wFFFLEFBFKNFaFCx/IFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBF8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBGy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBEn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBIi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBKI9z9iqlBOc+x8ycGBM/qQFTa8jUUUUBCU/EBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAGTkUUUBRNCUoBAG9uC/wgBZHKCUGAKCUG9JyRVAECFJRICBRcGXEXAcAF9PQFAVAFAclAcAVJAF9JyRMGXGXAG9FQBAMCbJHKC9wZRSAKCIrCEJCGrRQANCUGJRfCBRbAIRTEXGXAOATlAQ9PQBCBRISEMATAQJRIGXAS9FQBCBRtCBREEXGXAOAIlCi9PQBCBRISLMANCU/CBJAEJRKGXGXGXGXGXATAECKrJ2BBAtCKZrCEZfIBFGEBMAKhB83EBAKCNJhB83EBSEMAKAI2BIAI2BBHmCKrHYAYCE6HYy86BBAKCFJAICIJAYJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCGJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCEJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCIJAYAmJHY2BBAI2BFHmCKrHPAPCE6HPy86BBAKCLJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCKJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCOJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCNJAYAmJHY2BBAI2BGHmCKrHPAPCE6HPy86BBAKCVJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCcJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCMJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCSJAYAmJHm2BBAI2BEHICKrHYAYCE6HYy86BBAKCQJAmAYJHm2BBAICIrCEZHYAYCE6HYy86BBAKCfJAmAYJHm2BBAICGrCEZHYAYCE6HYy86BBAKCbJAmAYJHK2BBAICEZHIAICE6HIy86BBAKAIJRISGMAKAI2BNAI2BBHmCIrHYAYCb6HYy86BBAKCFJAICNJAYJHY2BBAmCbZHmAmCb6Hmy86BBAKCGJAYAmJHm2BBAI2BFHYCIrHPAPCb6HPy86BBAKCEJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCIJAmAYJHm2BBAI2BGHYCIrHPAPCb6HPy86BBAKCLJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCKJAmAYJHm2BBAI2BEHYCIrHPAPCb6HPy86BBAKCOJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCNJAmAYJHm2BBAI2BIHYCIrHPAPCb6HPy86BBAKCVJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCcJAmAYJHm2BBAI2BLHYCIrHPAPCb6HPy86BBAKCMJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCSJAmAYJHm2BBAI2BKHYCIrHPAPCb6HPy86BBAKCQJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCfJAmAYJHm2BBAI2BOHICIrHYAYCb6HYy86BBAKCbJAmAYJHK2BBAICbZHIAICb6HIy86BBAKAIJRISFMAKAI8pBB83BBAKCNJAICNJ8pBB83BBAICTJRIMAtCGJRtAECTJHEAS9JQBMMGXAIQBCBRISEMGXAM9FQBANAbJ2BBRtCBRKAfREEXAEANCU/CBJAKJ2BBHTCFrCBATCFZl9zAtJHt86BBAEAGJREAKCFJHKAM9HQBMMAfCFJRfAIRTAbCFJHbAG9HQBMMABAcAG9sJANCUGJAMAG9sTkUUUBpANANCUGJAMCaJAG9sJAGTkUUUBpMAMCBAIyAcJRcAIQBMC9+RKSFMCBC99AOAIlAGCAAGCA9Ly6yRKMALCU/EBJ8kUUUUBAKM+OmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUFT+JUUUBpALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM+lLKFaF99GaG99FaG99GXGXAGCI9HQBAF9FQFEXGXGX9DBBB8/9DBBB+/ABCGJHG1BB+yAB1BBHE+yHI+L+TABCFJHL1BBHK+yHO+L+THN9DBBBB9gHVyAN9DBB/+hANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE86BBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG86BBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG86BBABCIJRBAFCaJHFQBSGMMAF9FQBEXGXGX9DBBB8/9DBBB+/ABCIJHG8uFB+yAB8uFBHE+yHI+L+TABCGJHL8uFBHK+yHO+L+THN9DBBBB9gHVyAN9DB/+g6ANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE87FBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG87FBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG87FBABCNJRBAFCaJHFQBMMM/SEIEaE99EaF99GXAF9FQBCBREABRIEXGXGX9D/zI818/AICKJ8uFBHLCEq+y+VHKAI8uFB+y+UHO9DB/+g6+U9DBBB8/9DBBB+/AO9DBBBB9gy+SHN+L9DBBB9P9d9FQBAN+oRVSFMCUUUU94RVMAICIJ8uFBRcAICGJ8uFBRMABALCFJCEZAEqCFWJAV87FBGXGXAKAM+y+UHN9DB/+g6+U9DBBB8/9DBBB+/AN9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRMSFMCUUUU94RMMABALCGJCEZAEqCFWJAM87FBGXGXAKAc+y+UHK9DB/+g6+U9DBBB8/9DBBB+/AK9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRcSFMCUUUU94RcMABALCaJCEZAEqCFWJAc87FBGXGX9DBBU8/AOAO+U+TANAN+U+TAKAK+U+THO9DBBBBAO9DBBBB9gy+R9DB/+g6+U9DBBB8/+SHO+L9DBBB9P9d9FQBAO+oRcSFMCUUUU94RcMABALCEZAEqCFWJAc87FBAICNJRIAECIJREAFCaJHFQBMMM9JBGXAGCGrAF9sHF9FQBEXABAB8oGBHGCNWCN91+yAGCi91CnWCUUU/8EJ+++U84GBABCIJRBAFCaJHFQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEM/lFFFaGXGXAFABqCEZ9FQBABRESFMGXGXAGCT9PQBABRESFMABREEXAEAF8oGBjGBAECIJAFCIJ8oGBjGBAECNJAFCNJ8oGBjGBAECSJAFCSJ8oGBjGBAECTJREAFCTJRFAGC9wJHGCb9LQBMMAGCI9JQBEXAEAF8oGBjGBAFCIJRFAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF2BB86BBAECFJREAFCFJRFAGCaJHGQBMMABMoFFGaGXGXABCEZ9FQBABRESFMAFCgFZC+BwsN9sRIGXGXAGCT9PQBABRESFMABREEXAEAIjGBAECSJAIjGBAECNJAIjGBAECIJAIjGBAECTJREAGC9wJHGCb9LQBMMAGCI9JQBEXAEAIjGBAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF86BBAECFJREAGCaJHGQBMMABMMMFBCUNMIT9kBB"; const wasm_simd = "B9h9z9tFBBBFiI9gBB9gLaaaaaFa9gEaaaB9gFaFaEMcBBFBFFGGGEILF9wFFFLEFBFKNFaFCx/aFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBG8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBIy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBKi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBOn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBNI9z9iqlBVc+N9IcIBTEM9+FLa8jUUUUBCTlRBCBRFEXCBRGCBREEXABCNJAGJAECUaAFAGrCFZHIy86BBAEAIJREAGCFJHGCN9HQBMAFCx+YUUBJAE86BBAFCEWCxkUUBJAB8pEN83EBAFCFJHFCUG9HQBMMk8lLbaE97F9+FaL978jUUUUBCU/KBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAG/8cBBCUoBAG9uC/wgBZHKCUGAKCUG9JyRNAECFJRKCBRVGXEXAVAF9PQFANAFAVlAVANJAF9JyRcGXGXAG9FQBAcCbJHIC9wZHMCE9sRSAMCFWRQAICIrCEJCGrRfCBRbEXAKRTCBRtGXEXGXAOATlAf9PQBCBRKSLMALCU/CBJAtAM9sJRmATAfJRKCBREGXAMCoB9JQBAOAKlC/gB9JQBCBRIEXAmAIJREGXGXGXGXGXATAICKrJ2BBHYCEZfIBFGEBMAECBDtDMIBSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMIBAKCTJRKMGXGXGXGXGXAYCGrCEZfIBFGEBMAECBDtDMITSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMITAKCTJRKMGXGXGXGXGXAYCIrCEZfIBFGEBMAECBDtDMIASEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAEAKDBBBDMIAAKCTJRKMGXGXGXGXGXAYCKrfIBFGEBMAECBDtDMI8wSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCIJAeDeBJAYCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCNJAeDeBJAYCx+YUUBJ2BBJRKSFMAEAKDBBBDMI8wAKCTJRKMAICoBJREAICUFJAM9LQFAERIAOAKlC/fB9LQBMMGXAEAM9PQBAECErRIEXGXAOAKlCi9PQBCBRKSOMAmAEJRYGXGXGXGXGXATAECKrJ2BBAICKZrCEZfIBFGEBMAYCBDtDMIBSEMAYAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAeDeBJAiCx+YUUBJ2BBJRKSGMAYAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPAPDQBFGENVcMILKOSQfbHeD8dBh+BsxoxoUwN0AeD8dFhxoUwkwk+gUa0sHnhTkAnsHnhNkAnsHn7CgFZHiCEWCxkUUBJDBEBAiCx+YUUBJDBBBHeAeDQBBBBBBBBBBBBBBBBAnhAk7CgFZHiCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAeDeBJAiCx+YUUBJ2BBJRKSFMAYAKDBBBDMIBAKCTJRKMAICGJRIAECTJHEAM9JQBMMGXAK9FQBAKRTAtCFJHtCI6QGSFMMCBRKSEMGXAM9FQBALCUGJAbJREALAbJDBGBReCBRYEXAEALCU/CBJAYJHIDBIBHdCFD9tAdCFDbHPD9OD9hD9RHdAIAMJDBIBH8ZCFD9tA8ZAPD9OD9hD9RH8ZDQBTFtGmEYIPLdKeOnHpAIAQJDBIBHyCFD9tAyAPD9OD9hD9RHyAIASJDBIBH8cCFD9tA8cAPD9OD9hD9RH8cDQBTFtGmEYIPLdKeOnH8dDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGEAeD9uHeDyBjGBAEAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeApA8dDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeAdA8ZDQNiV8ZcpMyS8cQ8df8eb8fHdAyA8cDQNiV8ZcpMyS8cQ8df8eb8fH8ZDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJHIAeAdA8ZDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHeDyBjGBAIAGJHIAeAPAPDQILKOILKOILKOILKOD9uHeDyBjGBAIAGJHIAeAPAPDQNVcMNVcMNVcMNVcMD9uHeDyBjGBAIAGJHIAeAPAPDQSQfbSQfbSQfbSQfbD9uHeDyBjGBAIAGJREAYCTJHYAM9JQBMMAbCIJHbAG9JQBMMABAVAG9sJALCUGJAcAG9s/8cBBALALCUGJAcCaJAG9sJAG/8cBBMAcCBAKyAVJRVAKQBMC9+RKSFMCBC99AOAKlAGCAAGCA9Ly6yRKMALCU/KBJ8kUUUUBAKMNBT+BUUUBM+KmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUF/8MBALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM/dLEK97FaF97GXGXAGCI9HQBAF9FQFCBRGEXABABDBBBHECiD+rFCiD+sFD/6FHIAECND+rFCiD+sFD/6FAID/gFAECTD+rFCiD+sFD/6FHLD/gFD/kFD/lFHKCBDtD+2FHOAICUUUU94DtHND9OD9RD/kFHI9DBB/+hDYAIAID/mFAKAKD/mFALAOALAND9OD9RD/kFHIAID/mFD/kFD/kFD/jFD/nFHLD/mF9DBBX9LDYHOD/kFCgFDtD9OAECUUU94DtD9OD9QAIALD/mFAOD/kFCND+rFCU/+EDtD9OD9QAKALD/mFAOD/kFCTD+rFCUU/8ODtD9OD9QDMBBABCTJRBAGCIJHGAF9JQBSGMMAF9FQBCBRGEXABCTJHVAVDBBBHECBDtHOCUU98D8cFCUU98D8cEHND9OABDBBBHKAEDQILKOSQfbPden8c8d8e8fCggFDtD9OD/6FAKAEDQBFGENVcMTtmYi8ZpyHECTD+sFD/6FHID/gFAECTD+rFCTD+sFD/6FHLD/gFD/kFD/lFHE9DB/+g6DYALAEAOD+2FHOALCUUUU94DtHcD9OD9RD/kFHLALD/mFAEAED/mFAIAOAIAcD9OD9RD/kFHEAED/mFD/kFD/kFD/jFD/nFHID/mF9DBBX9LDYHOD/kFCTD+rFALAID/mFAOD/kFCggEDtD9OD9QHLAEAID/mFAOD/kFCaDbCBDnGCBDnECBDnKCBDnOCBDncCBDnMCBDnfCBDnbD9OHEDQNVi8ZcMpySQ8c8dfb8e8fD9QDMBBABAKAND9OALAEDQBFTtGEmYILPdKOenD9QDMBBABCAJRBAGCIJHGAF9JQBMMM/hEIGaF97FaL978jUUUUBCTlREGXAF9FQBCBRIEXAEABDBBBHLABCTJHKDBBBHODQILKOSQfbPden8c8d8e8fHNCTD+sFHVCID+rFDMIBAB9DBBU8/DY9D/zI818/DYAVCEDtD9QD/6FD/nFHVALAODQBFGENVcMTtmYi8ZpyHLCTD+rFCTD+sFD/6FD/mFHOAOD/mFAVALCTD+sFD/6FD/mFHcAcD/mFAVANCTD+rFCTD+sFD/6FD/mFHNAND/mFD/kFD/kFD/lFCBDtD+4FD/jF9DB/+g6DYHVD/mF9DBBX9LDYHLD/kFCggEDtHMD9OAcAVD/mFALD/kFCTD+rFD9QHcANAVD/mFALD/kFCTD+rFAOAVD/mFALD/kFAMD9OD9QHVDQBFTtGEmYILPdKOenHLD8dBAEDBIBDyB+t+J83EBABCNJALD8dFAEDBIBDyF+t+J83EBAKAcAVDQNVi8ZcMpySQ8c8dfb8e8fHVD8dBAEDBIBDyG+t+J83EBABCiJAVD8dFAEDBIBDyE+t+J83EBABCAJRBAICIJHIAF9JQBMMM9jFF97GXAGCGrAF9sHG9FQBCBRFEXABABDBBBHECND+rFCND+sFD/6FAECiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMBBABCTJRBAFCIJHFAG9JQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEMMMFBCUNMIT9tBB"; const detector = new Uint8Array([ 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 3, 2, 0, 0, 5, 3, 1, 0, 1, 12, 1, 0, 10, 22, 2, 12, 0, 65, 0, 65, 0, 65, 0, 252, 10, 0, 0, 11, 7, 0, 65, 0, 253, 15, 26, 11 ]); const wasmpack = new Uint8Array([ 32, 0, 65, 253, 3, 1, 2, 34, 4, 106, 6, 5, 11, 8, 7, 20, 13, 33, 12, 16, 128, 9, 116, 64, 19, 113, 127, 15, 10, 21, 22, 14, 255, 66, 24, 54, 136, 107, 18, 23, 192, 26, 114, 118, 132, 17, 77, 101, 130, 144, 27, 87, 131, 44, 45, 74, 156, 154, 70, 167 ]); if (typeof WebAssembly !== "object") return { supported: false }; let wasm = wasm_base; if (WebAssembly.validate(detector)) wasm = wasm_simd; let instance; const promise = WebAssembly.instantiate(unpack(wasm), {}).then((result) => { instance = result.instance; instance.exports.__wasm_call_ctors(); }); function unpack(data) { const result = new Uint8Array(data.length); for (let i = 0; i < data.length; ++i) { const ch = data.charCodeAt(i); result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; } let write = 0; for (let i = 0; i < data.length; ++i) result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; return result.buffer.slice(0, write); } function decode(fun, target, count, size, source, filter) { const sbrk = instance.exports.sbrk; const count4 = count + 3 & -4; const tp = sbrk(count4 * size); const sp = sbrk(source.length); const heap = new Uint8Array(instance.exports.memory.buffer); heap.set(source, sp); const res = fun(tp, count, size, sp, source.length); if (res === 0 && filter) filter(tp, count4, size); target.set(heap.subarray(tp, tp + count * size)); sbrk(tp - sbrk(0)); if (res !== 0) throw new Error(`Malformed buffer data: ${res}`); } const filters = { 0: "", 1: "meshopt_decodeFilterOct", 2: "meshopt_decodeFilterQuat", 3: "meshopt_decodeFilterExp", NONE: "", OCTAHEDRAL: "meshopt_decodeFilterOct", QUATERNION: "meshopt_decodeFilterQuat", EXPONENTIAL: "meshopt_decodeFilterExp" }; const decoders = { 0: "meshopt_decodeVertexBuffer", 1: "meshopt_decodeIndexBuffer", 2: "meshopt_decodeIndexSequence", ATTRIBUTES: "meshopt_decodeVertexBuffer", TRIANGLES: "meshopt_decodeIndexBuffer", INDICES: "meshopt_decodeIndexSequence" }; generated = { ready: promise, supported: true, decodeVertexBuffer(target, count, size, source, filter) { decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]); }, decodeIndexBuffer(target, count, size, source) { decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source); }, decodeIndexSequence(target, count, size, source) { decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source); }, decodeGltfBuffer(target, count, size, source, mode, filter) { decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); } }; return generated; }; //#endregion //#region node_modules/zustand/esm/vanilla/shallow.mjs var isIterable = (obj) => Symbol.iterator in obj; var hasIterableEntries = (value) => "entries" in value; var compareEntries = (valueA, valueB) => { const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries()); const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries()); if (mapA.size !== mapB.size) return false; for (const [key, value] of mapA) if (!mapB.has(key) || !Object.is(value, mapB.get(key))) return false; return true; }; var compareIterables = (valueA, valueB) => { const iteratorA = valueA[Symbol.iterator](); const iteratorB = valueB[Symbol.iterator](); let nextA = iteratorA.next(); let nextB = iteratorB.next(); while (!nextA.done && !nextB.done) { if (!Object.is(nextA.value, nextB.value)) return false; nextA = iteratorA.next(); nextB = iteratorB.next(); } return !!nextA.done && !!nextB.done; }; function shallow(valueA, valueB) { if (Object.is(valueA, valueB)) return true; if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) return false; if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) return false; if (isIterable(valueA) && isIterable(valueB)) { if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) return compareEntries(valueA, valueB); return compareIterables(valueA, valueB); } return compareEntries({ entries: () => Object.entries(valueA) }, { entries: () => Object.entries(valueB) }); } //#endregion //#region node_modules/@react-three/drei/web/Select.js var context$7 = /* @__PURE__ */ import_react.createContext([]); function Select({ box, multiple, children, onChange, onChangePointerUp, border = "1px solid #55aaff", backgroundColor = "rgba(75, 160, 255, 0.1)", filter: customFilter = (item) => item, ...props }) { const [downed, down] = import_react.useState(false); const { setEvents, camera, raycaster, gl, controls, size, get } = useThree(); const [hovered, hover] = import_react.useState(false); const [active, dispatch] = import_react.useReducer((state, { object, shift }) => { if (object === void 0) return []; else if (Array.isArray(object)) return object; else if (!shift) return state[0] === object ? [] : [object]; else if (state.includes(object)) return state.filter((o) => o !== object); else return [object, ...state]; }, []); import_react.useEffect(() => { if (downed) onChange?.(active); else onChangePointerUp?.(active); }, [active, downed]); const onClick = import_react.useCallback((e) => { e.stopPropagation(); dispatch({ object: customFilter([e.object])[0], shift: multiple && e.shiftKey }); }, []); const onPointerMissed = import_react.useCallback((e) => !hovered && dispatch({}), [hovered]); const ref = import_react.useRef(null); import_react.useEffect(() => { if (!box || !multiple) return; const selBox = new SelectionBox(camera, ref.current); const element = document.createElement("div"); element.style.pointerEvents = "none"; element.style.border = border; element.style.backgroundColor = backgroundColor; element.style.position = "fixed"; const startPoint = new Vector2(); const pointTopLeft = new Vector2(); const pointBottomRight = new Vector2(); const oldRaycasterEnabled = get().events.enabled; const oldControlsEnabled = controls == null ? void 0 : controls.enabled; let isDown = false; function prepareRay(event, vec) { const { offsetX, offsetY } = event; const { width, height } = size; vec.set(offsetX / width * 2 - 1, -(offsetY / height) * 2 + 1); } function onSelectStart(event) { var _gl$domElement$parent; if (controls) controls.enabled = false; setEvents({ enabled: false }); down(isDown = true); (_gl$domElement$parent = gl.domElement.parentElement) == null || _gl$domElement$parent.appendChild(element); element.style.left = `${event.clientX}px`; element.style.top = `${event.clientY}px`; element.style.width = "0px"; element.style.height = "0px"; startPoint.x = event.clientX; startPoint.y = event.clientY; } function onSelectMove(event) { pointBottomRight.x = Math.max(startPoint.x, event.clientX); pointBottomRight.y = Math.max(startPoint.y, event.clientY); pointTopLeft.x = Math.min(startPoint.x, event.clientX); pointTopLeft.y = Math.min(startPoint.y, event.clientY); element.style.left = `${pointTopLeft.x}px`; element.style.top = `${pointTopLeft.y}px`; element.style.width = `${pointBottomRight.x - pointTopLeft.x}px`; element.style.height = `${pointBottomRight.y - pointTopLeft.y}px`; } function onSelectOver() { if (isDown) { var _element$parentElemen; if (controls) controls.enabled = oldControlsEnabled; setEvents({ enabled: oldRaycasterEnabled }); down(isDown = false); (_element$parentElemen = element.parentElement) == null || _element$parentElemen.removeChild(element); } } function pointerDown(event) { if (event.shiftKey) { onSelectStart(event); prepareRay(event, selBox.startPoint); } } let previous = []; function pointerMove(event) { if (isDown) { onSelectMove(event); prepareRay(event, selBox.endPoint); const allSelected = selBox.select().sort((o) => o.uuid).filter((o) => o.isMesh); if (!shallow(allSelected, previous)) { previous = allSelected; dispatch({ object: customFilter(allSelected) }); } } } function pointerUp(event) { if (isDown) onSelectOver(); } document.addEventListener("pointerdown", pointerDown, { passive: true }); document.addEventListener("pointermove", pointerMove, { passive: true, capture: true }); document.addEventListener("pointerup", pointerUp, { passive: true }); return () => { document.removeEventListener("pointerdown", pointerDown); document.removeEventListener("pointermove", pointerMove, true); document.removeEventListener("pointerup", pointerUp); }; }, [ size.width, size.height, raycaster, camera, controls, gl ]); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref, onClick, onPointerOver: () => hover(true), onPointerOut: () => hover(false), onPointerMissed }, props), /*#__PURE__*/ import_react.createElement(context$7.Provider, { value: active }, children)); } function useSelect() { return import_react.useContext(context$7); } //#endregion //#region node_modules/@react-three/drei/core/Billboard.js /** * Wraps children in a billboarded group. Sample usage: * * ```js * * hi * * ``` */ var Billboard = /* @__PURE__ */ import_react.forwardRef(function Billboard({ children, follow = true, lockX = false, lockY = false, lockZ = false, ...props }, fref) { const inner = import_react.useRef(null); const localRef = import_react.useRef(null); const q = new Quaternion(); useFrame(({ camera }) => { if (!follow || !localRef.current) return; const prevRotation = inner.current.rotation.clone(); localRef.current.updateMatrix(); localRef.current.updateWorldMatrix(false, false); localRef.current.getWorldQuaternion(q); camera.getWorldQuaternion(inner.current.quaternion).premultiply(q.invert()); if (lockX) inner.current.rotation.x = prevRotation.x; if (lockY) inner.current.rotation.y = prevRotation.y; if (lockZ) inner.current.rotation.z = prevRotation.z; }); import_react.useImperativeHandle(fref, () => localRef.current, []); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: localRef }, props), /*#__PURE__*/ import_react.createElement("group", { ref: inner }, children)); }); //#endregion //#region node_modules/@react-three/drei/core/ScreenSpace.js var ScreenSpace = /* @__PURE__ */ import_react.forwardRef(({ children, depth = -1, ...rest }, ref) => { const localRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => localRef.current, []); useFrame(({ camera }) => { localRef.current.quaternion.copy(camera.quaternion); localRef.current.position.copy(camera.position); }); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: localRef }, rest), /*#__PURE__*/ import_react.createElement("group", { "position-z": -depth }, children)); }); //#endregion //#region node_modules/@react-three/drei/core/calculateScaleFactor.js var tV0 = /* @__PURE__ */ new Vector3(); var tV1 = /* @__PURE__ */ new Vector3(); var tV2 = /* @__PURE__ */ new Vector3(); var getPoint2 = (point3, camera, size) => { const widthHalf = size.width / 2; const heightHalf = size.height / 2; camera.updateMatrixWorld(false); const vector = point3.project(camera); vector.x = vector.x * widthHalf + widthHalf; vector.y = -(vector.y * heightHalf) + heightHalf; return vector; }; var getPoint3 = (point2, camera, size, zValue = 1) => { const vector = tV0.set(point2.x / size.width * 2 - 1, -(point2.y / size.height) * 2 + 1, zValue); vector.unproject(camera); return vector; }; var calculateScaleFactor = (point3, radiusPx, camera, size) => { const point2 = getPoint2(tV2.copy(point3), camera, size); let scale = 0; for (let i = 0; i < 2; ++i) { const point2off = tV1.copy(point2).setComponent(i, point2.getComponent(i) + radiusPx); const point3off = getPoint3(point2off, camera, size, point2off.z); scale = Math.max(scale, point3.distanceTo(point3off)); } return scale; }; //#endregion //#region node_modules/@react-three/drei/core/ScreenSizer.js var worldPos = /* @__PURE__ */ new Vector3(); /** * Wraps children in an `Object3D` and attempts to scale from * world units to screen units * scale factor. * * For example, this will render a box of roughly 1x1 pixel size, * independently of how far the camera is. * * ```jsx * * * * ``` */ var ScreenSizer = /* @__PURE__ */ (0, import_react.forwardRef)(({ scale = 1, ...props }, ref) => { const container = (0, import_react.useRef)(null); import_react.useImperativeHandle(ref, () => container.current, []); useFrame((state) => { const obj = container.current; if (!obj) return; const sf = calculateScaleFactor(obj.getWorldPosition(worldPos), scale, state.camera, state.size); obj.scale.setScalar(sf * scale); }); return /*#__PURE__*/ import_react.createElement("object3D", _extends$1({ ref: container }, props)); }); //#endregion //#region node_modules/@react-three/drei/core/Line.js var Line = /* @__PURE__ */ import_react.forwardRef(function Line({ points, color = 16777215, vertexColors, linewidth, lineWidth, segments, dashed, ...rest }, ref) { var _vertexColors$, _ref; const size = useThree((state) => state.size); const line2 = import_react.useMemo(() => segments ? new LineSegments2() : new Line2(), [segments]); const [lineMaterial] = import_react.useState(() => new LineMaterial()); const itemSize = (vertexColors == null || (_vertexColors$ = vertexColors[0]) == null ? void 0 : _vertexColors$.length) === 4 ? 4 : 3; const lineGeom = import_react.useMemo(() => { const geom = segments ? new LineSegmentsGeometry() : new LineGeometry(); const pValues = points.map((p) => { const isArray = Array.isArray(p); return p instanceof Vector3 || p instanceof Vector4 ? [ p.x, p.y, p.z ] : p instanceof Vector2 ? [ p.x, p.y, 0 ] : isArray && p.length === 3 ? [ p[0], p[1], p[2] ] : isArray && p.length === 2 ? [ p[0], p[1], 0 ] : p; }); geom.setPositions(pValues.flat()); if (vertexColors) { color = 16777215; const cValues = vertexColors.map((c) => c instanceof Color ? c.toArray() : c); geom.setColors(cValues.flat(), itemSize); } return geom; }, [ points, segments, vertexColors, itemSize ]); import_react.useLayoutEffect(() => { line2.computeLineDistances(); }, [points, line2]); import_react.useLayoutEffect(() => { if (dashed) lineMaterial.defines.USE_DASH = ""; else delete lineMaterial.defines.USE_DASH; lineMaterial.needsUpdate = true; }, [dashed, lineMaterial]); import_react.useEffect(() => { return () => { lineGeom.dispose(); lineMaterial.dispose(); }; }, [lineGeom]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: line2, ref }, rest), /*#__PURE__*/ import_react.createElement("primitive", { object: lineGeom, attach: "geometry" }), /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: lineMaterial, attach: "material", color, vertexColors: Boolean(vertexColors), resolution: [size.width, size.height], linewidth: (_ref = linewidth !== null && linewidth !== void 0 ? linewidth : lineWidth) !== null && _ref !== void 0 ? _ref : 1, dashed, transparent: itemSize === 4 }, rest))); }); //#endregion //#region node_modules/@react-three/drei/core/QuadraticBezierLine.js var v = /* @__PURE__ */ new Vector3(); var QuadraticBezierLine = /* @__PURE__ */ import_react.forwardRef(function QuadraticBezierLine({ start = [ 0, 0, 0 ], end = [ 0, 0, 0 ], mid, segments = 20, ...rest }, forwardref) { const ref = import_react.useRef(null); import_react.useImperativeHandle(forwardref, () => ref.current); const [curve] = import_react.useState(() => new QuadraticBezierCurve3(void 0, void 0, void 0)); const getPoints = import_react.useCallback((start, end, mid, segments = 20) => { if (start instanceof Vector3) curve.v0.copy(start); else curve.v0.set(...start); if (end instanceof Vector3) curve.v2.copy(end); else curve.v2.set(...end); if (mid instanceof Vector3) curve.v1.copy(mid); else if (Array.isArray(mid)) curve.v1.set(...mid); else curve.v1.copy(curve.v0.clone().add(curve.v2.clone().sub(curve.v0)).add(v.set(0, curve.v0.y - curve.v2.y, 0))); return curve.getPoints(segments); }, []); import_react.useLayoutEffect(() => { ref.current.setPoints = (start, end, mid) => { const points = getPoints(start, end, mid); if (ref.current.geometry) ref.current.geometry.setPositions(points.map((p) => p.toArray()).flat()); }; }, []); const points = import_react.useMemo(() => getPoints(start, end, mid, segments), [ start, end, mid, segments ]); return /*#__PURE__*/ import_react.createElement(Line, _extends$1({ ref, points }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/CubicBezierLine.js var CubicBezierLine = /* @__PURE__ */ import_react.forwardRef(function CubicBezierLine({ start, end, midA, midB, segments = 20, ...rest }, ref) { const points = import_react.useMemo(() => { const startV = start instanceof Vector3 ? start : new Vector3(...start); const endV = end instanceof Vector3 ? end : new Vector3(...end); return new CubicBezierCurve3(startV, midA instanceof Vector3 ? midA : new Vector3(...midA), midB instanceof Vector3 ? midB : new Vector3(...midB), endV).getPoints(segments); }, [ start, end, midA, midB, segments ]); return /*#__PURE__*/ import_react.createElement(Line, _extends$1({ ref, points }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/CatmullRomLine.js var CatmullRomLine = /* @__PURE__ */ import_react.forwardRef(function CatmullRomLine({ points, closed = false, curveType = "centripetal", tension = .5, segments = 20, vertexColors, ...rest }, ref) { const curve = import_react.useMemo(() => { return new CatmullRomCurve3(points.map((pt) => pt instanceof Vector3 ? pt : new Vector3(...pt)), closed, curveType, tension); }, [ points, closed, curveType, tension ]); const segmentedPoints = import_react.useMemo(() => curve.getPoints(segments), [curve, segments]); const interpolatedVertexColors = import_react.useMemo(() => { if (!vertexColors || vertexColors.length < 2) return void 0; if (vertexColors.length === segments + 1) return vertexColors; const mappedColors = vertexColors.map((color) => color instanceof Color ? color : new Color(...color)); if (closed) mappedColors.push(mappedColors[0].clone()); const iColors = [mappedColors[0]]; const divisions = segments / (mappedColors.length - 1); for (let i = 1; i < segments; i++) { const alpha = i % divisions / divisions; const colorIndex = Math.floor(i / divisions); iColors.push(mappedColors[colorIndex].clone().lerp(mappedColors[colorIndex + 1], alpha)); } iColors.push(mappedColors[mappedColors.length - 1]); return iColors; }, [vertexColors, segments]); return /*#__PURE__*/ import_react.createElement(Line, _extends$1({ ref, points: segmentedPoints, vertexColors: interpolatedVertexColors }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/PositionalAudio.js var PositionalAudio = /* @__PURE__ */ import_react.forwardRef(({ url, distance = 1, loop = true, autoplay, ...props }, ref) => { const sound = import_react.useRef(null); import_react.useImperativeHandle(ref, () => sound.current, []); const camera = useThree(({ camera }) => camera); const [listener] = import_react.useState(() => new AudioListener()); const buffer = useLoader(AudioLoader, url); import_react.useEffect(() => { const _sound = sound.current; if (_sound) { _sound.setBuffer(buffer); _sound.setRefDistance(distance); _sound.setLoop(loop); if (autoplay && !_sound.isPlaying) _sound.play(); } }, [ buffer, camera, distance, loop ]); import_react.useEffect(() => { const _sound = sound.current; camera.add(listener); return () => { camera.remove(listener); if (_sound) { if (_sound.isPlaying) _sound.stop(); if (_sound.source && _sound.source._connected) _sound.disconnect(); } }; }, []); return /*#__PURE__*/ import_react.createElement("positionalAudio", _extends$1({ ref: sound, args: [listener] }, props)); }); //#endregion //#region node_modules/troika-worker-utils/dist/troika-worker-utils.esm.js /** * Main content for the worker that handles the loading and execution of * modules within it. */ function workerBootstrap() { var modules = Object.create(null); function registerModule(ref, callback) { var id = ref.id; var name = ref.name; var dependencies = ref.dependencies; if (dependencies === void 0) dependencies = []; var init = ref.init; if (init === void 0) init = function() {}; var getTransferables = ref.getTransferables; if (getTransferables === void 0) getTransferables = null; if (modules[id]) return; try { dependencies = dependencies.map(function(dep) { if (dep && dep.isWorkerModule) { registerModule(dep, function(depResult) { if (depResult instanceof Error) throw depResult; }); dep = modules[dep.id].value; } return dep; }); init = rehydrate("<" + name + ">.init", init); if (getTransferables) getTransferables = rehydrate("<" + name + ">.getTransferables", getTransferables); var value = null; if (typeof init === "function") value = init.apply(void 0, dependencies); else console.error("worker module init function failed to rehydrate"); modules[id] = { id, value, getTransferables }; callback(value); } catch (err) { if (!(err && err.noLog)) console.error(err); callback(err); } } function callModule(ref, callback) { var ref$1; var id = ref.id; var args = ref.args; if (!modules[id] || typeof modules[id].value !== "function") callback(/* @__PURE__ */ new Error("Worker module " + id + ": not found or its 'init' did not return a function")); try { var result = (ref$1 = modules[id]).value.apply(ref$1, args); if (result && typeof result.then === "function") result.then(handleResult, function(rej) { return callback(rej instanceof Error ? rej : /* @__PURE__ */ new Error("" + rej)); }); else handleResult(result); } catch (err) { callback(err); } function handleResult(result) { try { var tx = modules[id].getTransferables && modules[id].getTransferables(result); if (!tx || !Array.isArray(tx) || !tx.length) tx = void 0; callback(result, tx); } catch (err) { console.error(err); callback(err); } } } function rehydrate(name, str) { var result = void 0; self.troikaDefine = function(r) { return result = r; }; var url = URL.createObjectURL(new Blob(["/** " + name.replace(/\*/g, "") + " **/\n\ntroikaDefine(\n" + str + "\n)"], { type: "application/javascript" })); try { importScripts(url); } catch (err) { console.error(err); } URL.revokeObjectURL(url); delete self.troikaDefine; return result; } self.addEventListener("message", function(e) { var ref = e.data; var messageId = ref.messageId; var action = ref.action; var data = ref.data; try { if (action === "registerModule") registerModule(data, function(result) { if (result instanceof Error) postMessage({ messageId, success: false, error: result.message }); else postMessage({ messageId, success: true, result: { isCallable: typeof result === "function" } }); }); if (action === "callModule") callModule(data, function(result, transferables) { if (result instanceof Error) postMessage({ messageId, success: false, error: result.message }); else postMessage({ messageId, success: true, result }, transferables || void 0); }); } catch (err) { postMessage({ messageId, success: false, error: err.stack }); } }); } /** * Fallback for `defineWorkerModule` that behaves identically but runs in the main * thread, for when the execution environment doesn't support web workers or they * are disallowed due to e.g. CSP security restrictions. */ function defineMainThreadModule(options) { var moduleFunc = function() { var args = [], len = arguments.length; while (len--) args[len] = arguments[len]; return moduleFunc._getInitResult().then(function(initResult) { if (typeof initResult === "function") return initResult.apply(void 0, args); else throw new Error("Worker module function was called but `init` did not return a callable function"); }); }; moduleFunc._getInitResult = function() { var dependencies = options.dependencies; var init = options.init; dependencies = Array.isArray(dependencies) ? dependencies.map(function(dep) { if (dep) { dep = dep.onMainThread || dep; if (dep._getInitResult) dep = dep._getInitResult(); } return dep; }) : []; var initPromise = Promise.all(dependencies).then(function(deps) { return init.apply(null, deps); }); moduleFunc._getInitResult = function() { return initPromise; }; return initPromise; }; return moduleFunc; } var supportsWorkers = function() { var supported = false; if (typeof window !== "undefined" && typeof window.document !== "undefined") try { new Worker(URL.createObjectURL(new Blob([""], { type: "application/javascript" }))).terminate(); supported = true; } catch (err) { console.log("Troika createWorkerModule: web workers not allowed; falling back to main thread execution. Cause: [" + err.message + "]"); } supportsWorkers = function() { return supported; }; return supported; }; var _workerModuleId = 0; var _messageId = 0; var _allowInitAsString = false; var workers = Object.create(null); var registeredModules = Object.create(null); var openRequests = Object.create(null); /** * Define a module of code that will be executed with a web worker. This provides a simple * interface for moving chunks of logic off the main thread, and managing their dependencies * among one another. * * @param {object} options * @param {function} options.init * @param {array} [options.dependencies] * @param {function} [options.getTransferables] * @param {string} [options.name] * @param {string} [options.workerId] * @return {function(...[*]): {then}} */ function defineWorkerModule(options) { if ((!options || typeof options.init !== "function") && !_allowInitAsString) throw new Error("requires `options.init` function"); var dependencies = options.dependencies; var init = options.init; var getTransferables = options.getTransferables; var workerId = options.workerId; var onMainThread = defineMainThreadModule(options); if (workerId == null) workerId = "#default"; var id = "workerModule" + ++_workerModuleId; var name = options.name || id; var registrationPromise = null; dependencies = dependencies && dependencies.map(function(dep) { if (typeof dep === "function" && !dep.workerModuleData) { _allowInitAsString = true; dep = defineWorkerModule({ workerId, name: "<" + name + "> function dependency: " + dep.name, init: "function(){return (\n" + stringifyFunction(dep) + "\n)}" }); _allowInitAsString = false; } if (dep && dep.workerModuleData) dep = dep.workerModuleData; return dep; }); function moduleFunc() { var args = [], len = arguments.length; while (len--) args[len] = arguments[len]; if (!supportsWorkers()) return onMainThread.apply(void 0, args); if (!registrationPromise) { registrationPromise = callWorker(workerId, "registerModule", moduleFunc.workerModuleData); var unregister = function() { registrationPromise = null; registeredModules[workerId].delete(unregister); }; (registeredModules[workerId] || (registeredModules[workerId] = /* @__PURE__ */ new Set())).add(unregister); } return registrationPromise.then(function(ref) { if (ref.isCallable) return callWorker(workerId, "callModule", { id, args }); else throw new Error("Worker module function was called but `init` did not return a callable function"); }); } moduleFunc.workerModuleData = { isWorkerModule: true, id, name, dependencies, init: stringifyFunction(init), getTransferables: getTransferables && stringifyFunction(getTransferables) }; moduleFunc.onMainThread = onMainThread; return moduleFunc; } /** * Terminate an active Worker by a workerId that was passed to defineWorkerModule. * This only terminates the Worker itself; the worker module will remain available * and if you call it again its Worker will be respawned. * @param {string} workerId */ function terminateWorker(workerId) { if (registeredModules[workerId]) registeredModules[workerId].forEach(function(unregister) { unregister(); }); if (workers[workerId]) { workers[workerId].terminate(); delete workers[workerId]; } } /** * Stringifies a function into a form that can be deserialized in the worker * @param fn */ function stringifyFunction(fn) { var str = fn.toString(); if (!/^function/.test(str) && /^\w+\s*\(/.test(str)) str = "function " + str; return str; } function getWorker(workerId) { var worker = workers[workerId]; if (!worker) { var bootstrap = stringifyFunction(workerBootstrap); worker = workers[workerId] = new Worker(URL.createObjectURL(new Blob(["/** Worker Module Bootstrap: " + workerId.replace(/\*/g, "") + " **/\n\n;(" + bootstrap + ")()"], { type: "application/javascript" }))); worker.onmessage = function(e) { var response = e.data; var msgId = response.messageId; var callback = openRequests[msgId]; if (!callback) throw new Error("WorkerModule response with empty or unknown messageId"); delete openRequests[msgId]; callback(response); }; } return worker; } function callWorker(workerId, action, data) { return new Promise(function(resolve, reject) { var messageId = ++_messageId; openRequests[messageId] = function(response) { if (response.success) resolve(response.result); else reject(/* @__PURE__ */ new Error("Error in worker " + action + " call: " + response.error)); }; getWorker(workerId).postMessage({ messageId, action, data }); }); } //#endregion //#region node_modules/webgl-sdf-generator/dist/webgl-sdf-generator.mjs function SDFGenerator() { return function(exports) { /** * Find the point on a quadratic bezier curve at t where t is in the range [0, 1] */ function pointOnQuadraticBezier(x0, y0, x1, y1, x2, y2, t, pointOut) { var t2 = 1 - t; pointOut.x = t2 * t2 * x0 + 2 * t2 * t * x1 + t * t * x2; pointOut.y = t2 * t2 * y0 + 2 * t2 * t * y1 + t * t * y2; } /** * Find the point on a cubic bezier curve at t where t is in the range [0, 1] */ function pointOnCubicBezier(x0, y0, x1, y1, x2, y2, x3, y3, t, pointOut) { var t2 = 1 - t; pointOut.x = t2 * t2 * t2 * x0 + 3 * t2 * t2 * t * x1 + 3 * t2 * t * t * x2 + t * t * t * x3; pointOut.y = t2 * t2 * t2 * y0 + 3 * t2 * t2 * t * y1 + 3 * t2 * t * t * y2 + t * t * t * y3; } /** * Parse a path string into its constituent line/curve commands, invoking a callback for each. * @param {string} pathString - An SVG-like path string to parse; should only contain commands: M/L/Q/C/Z * @param {function( * command: 'L'|'Q'|'C', * startX: number, * startY: number, * endX: number, * endY: number, * ctrl1X?: number, * ctrl1Y?: number, * ctrl2X?: number, * ctrl2Y?: number * )} commandCallback - A callback function that will be called once for each parsed path command, passing the * command identifier (only L/Q/C commands) and its numeric arguments. */ function forEachPathCommand(pathString, commandCallback) { var segmentRE = /([MLQCZ])([^MLQCZ]*)/g; var match, firstX, firstY, prevX, prevY; while (match = segmentRE.exec(pathString)) { var args = match[2].replace(/^\s*|\s*$/g, "").split(/[,\s]+/).map(function(v) { return parseFloat(v); }); switch (match[1]) { case "M": prevX = firstX = args[0]; prevY = firstY = args[1]; break; case "L": if (args[0] !== prevX || args[1] !== prevY) commandCallback("L", prevX, prevY, prevX = args[0], prevY = args[1]); break; case "Q": commandCallback("Q", prevX, prevY, prevX = args[2], prevY = args[3], args[0], args[1]); break; case "C": commandCallback("C", prevX, prevY, prevX = args[4], prevY = args[5], args[0], args[1], args[2], args[3]); break; case "Z": if (prevX !== firstX || prevY !== firstY) commandCallback("L", prevX, prevY, firstX, firstY); break; } } } /** * Convert a path string to a series of straight line segments * @param {string} pathString - An SVG-like path string to parse; should only contain commands: M/L/Q/C/Z * @param {function(x1:number, y1:number, x2:number, y2:number)} segmentCallback - A callback * function that will be called once for every line segment * @param {number} [curvePoints] - How many straight line segments to use when approximating a * bezier curve in the path. Defaults to 16. */ function pathToLineSegments(pathString, segmentCallback, curvePoints) { if (curvePoints === void 0) curvePoints = 16; var tempPoint = { x: 0, y: 0 }; forEachPathCommand(pathString, function(command, startX, startY, endX, endY, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y) { switch (command) { case "L": segmentCallback(startX, startY, endX, endY); break; case "Q": var prevCurveX = startX; var prevCurveY = startY; for (var i = 1; i < curvePoints; i++) { pointOnQuadraticBezier(startX, startY, ctrl1X, ctrl1Y, endX, endY, i / (curvePoints - 1), tempPoint); segmentCallback(prevCurveX, prevCurveY, tempPoint.x, tempPoint.y); prevCurveX = tempPoint.x; prevCurveY = tempPoint.y; } break; case "C": var prevCurveX$1 = startX; var prevCurveY$1 = startY; for (var i$1 = 1; i$1 < curvePoints; i$1++) { pointOnCubicBezier(startX, startY, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, endX, endY, i$1 / (curvePoints - 1), tempPoint); segmentCallback(prevCurveX$1, prevCurveY$1, tempPoint.x, tempPoint.y); prevCurveX$1 = tempPoint.x; prevCurveY$1 = tempPoint.y; } break; } }); } var viewportQuadVertex = "precision highp float;attribute vec2 aUV;varying vec2 vUV;void main(){vUV=aUV;gl_Position=vec4(mix(vec2(-1.0),vec2(1.0),aUV),0.0,1.0);}"; var copyTexFragment = "precision highp float;uniform sampler2D tex;varying vec2 vUV;void main(){gl_FragColor=texture2D(tex,vUV);}"; var cache = /* @__PURE__ */ new WeakMap(); var glContextParams = { premultipliedAlpha: false, preserveDrawingBuffer: true, antialias: false, depth: false }; /** * This is a little helper library for WebGL. It assists with state management for a GL context. * It's pretty tightly wrapped to the needs of this package, not very general-purpose. * * @param { WebGLRenderingContext | HTMLCanvasElement | OffscreenCanvas } glOrCanvas - the GL context to wrap * @param { ({gl, getExtension, withProgram, withTexture, withTextureFramebuffer, handleContextLoss}) => void } callback */ function withWebGLContext(glOrCanvas, callback) { var gl = glOrCanvas.getContext ? glOrCanvas.getContext("webgl", glContextParams) : glOrCanvas; var wrapper = cache.get(gl); if (!wrapper) { var isWebGL2 = typeof WebGL2RenderingContext !== "undefined" && gl instanceof WebGL2RenderingContext; var extensions = {}; var programs = {}; var textures = {}; var textureUnit = -1; var framebufferStack = []; gl.canvas.addEventListener("webglcontextlost", function(e) { handleContextLoss(); e.preventDefault(); }, false); function getExtension(name) { var ext = extensions[name]; if (!ext) { ext = extensions[name] = gl.getExtension(name); if (!ext) throw new Error(name + " not supported"); } return ext; } function compileShader(src, type) { var shader = gl.createShader(type); gl.shaderSource(shader, src); gl.compileShader(shader); return shader; } function withProgram(name, vert, frag, func) { if (!programs[name]) { var attributes = {}; var uniforms = {}; var program = gl.createProgram(); gl.attachShader(program, compileShader(vert, gl.VERTEX_SHADER)); gl.attachShader(program, compileShader(frag, gl.FRAGMENT_SHADER)); gl.linkProgram(program); programs[name] = { program, transaction: function transaction(func) { gl.useProgram(program); func({ setUniform: function setUniform(type, name) { var values = [], len = arguments.length - 2; while (len-- > 0) values[len] = arguments[len + 2]; var uniformLoc = uniforms[name] || (uniforms[name] = gl.getUniformLocation(program, name)); gl["uniform" + type].apply(gl, [uniformLoc].concat(values)); }, setAttribute: function setAttribute(name, size, usage, instancingDivisor, data) { var attr = attributes[name]; if (!attr) attr = attributes[name] = { buf: gl.createBuffer(), loc: gl.getAttribLocation(program, name), data: null }; gl.bindBuffer(gl.ARRAY_BUFFER, attr.buf); gl.vertexAttribPointer(attr.loc, size, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(attr.loc); if (isWebGL2) gl.vertexAttribDivisor(attr.loc, instancingDivisor); else getExtension("ANGLE_instanced_arrays").vertexAttribDivisorANGLE(attr.loc, instancingDivisor); if (data !== attr.data) { gl.bufferData(gl.ARRAY_BUFFER, data, usage); attr.data = data; } } }); } }; } programs[name].transaction(func); } function withTexture(name, func) { textureUnit++; try { gl.activeTexture(gl.TEXTURE0 + textureUnit); var texture = textures[name]; if (!texture) { texture = textures[name] = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); } gl.bindTexture(gl.TEXTURE_2D, texture); func(texture, textureUnit); } finally { textureUnit--; } } function withTextureFramebuffer(texture, textureUnit, func) { var framebuffer = gl.createFramebuffer(); framebufferStack.push(framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.activeTexture(gl.TEXTURE0 + textureUnit); gl.bindTexture(gl.TEXTURE_2D, texture); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); try { func(framebuffer); } finally { gl.deleteFramebuffer(framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferStack[--framebufferStack.length - 1] || null); } } function handleContextLoss() { extensions = {}; programs = {}; textures = {}; textureUnit = -1; framebufferStack.length = 0; } cache.set(gl, wrapper = { gl, isWebGL2, getExtension, withProgram, withTexture, withTextureFramebuffer, handleContextLoss }); } callback(wrapper); } function renderImageData(glOrCanvas, imageData, x, y, width, height, channels, framebuffer) { if (channels === void 0) channels = 15; if (framebuffer === void 0) framebuffer = null; withWebGLContext(glOrCanvas, function(ref) { var gl = ref.gl; var withProgram = ref.withProgram; var withTexture = ref.withTexture; withTexture("copy", function(tex, texUnit) { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData); withProgram("copy", viewportQuadVertex, copyTexFragment, function(ref) { var setUniform = ref.setUniform; var setAttribute = ref.setAttribute; setAttribute("aUV", 2, gl.STATIC_DRAW, 0, new Float32Array([ 0, 0, 2, 0, 0, 2 ])); setUniform("1i", "image", texUnit); gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer || null); gl.disable(gl.BLEND); gl.colorMask(channels & 8, channels & 4, channels & 2, channels & 1); gl.viewport(x, y, width, height); gl.scissor(x, y, width, height); gl.drawArrays(gl.TRIANGLES, 0, 3); }); }); }); } /** * Resizing a canvas clears its contents; this utility copies the previous contents over. * @param canvas * @param newWidth * @param newHeight */ function resizeWebGLCanvasWithoutClearing(canvas, newWidth, newHeight) { var width = canvas.width; var height = canvas.height; withWebGLContext(canvas, function(ref) { var gl = ref.gl; var data = new Uint8Array(width * height * 4); gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data); canvas.width = newWidth; canvas.height = newHeight; renderImageData(gl, data, 0, 0, width, height); }); } var webglUtils = /*#__PURE__*/ Object.freeze({ __proto__: null, withWebGLContext, renderImageData, resizeWebGLCanvasWithoutClearing }); function generate$2(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent) { if (sdfExponent === void 0) sdfExponent = 1; var textureData = new Uint8Array(sdfWidth * sdfHeight); var viewBoxWidth = viewBox[2] - viewBox[0]; var viewBoxHeight = viewBox[3] - viewBox[1]; var segments = []; pathToLineSegments(path, function(x1, y1, x2, y2) { segments.push({ x1, y1, x2, y2, minX: Math.min(x1, x2), minY: Math.min(y1, y2), maxX: Math.max(x1, x2), maxY: Math.max(y1, y2) }); }); segments.sort(function(a, b) { return a.maxX - b.maxX; }); for (var sdfX = 0; sdfX < sdfWidth; sdfX++) for (var sdfY = 0; sdfY < sdfHeight; sdfY++) { var signedDist = findNearestSignedDistance(viewBox[0] + viewBoxWidth * (sdfX + .5) / sdfWidth, viewBox[1] + viewBoxHeight * (sdfY + .5) / sdfHeight); var alpha = Math.pow(1 - Math.abs(signedDist) / maxDistance, sdfExponent) / 2; if (signedDist < 0) alpha = 1 - alpha; alpha = Math.max(0, Math.min(255, Math.round(alpha * 255))); textureData[sdfY * sdfWidth + sdfX] = alpha; } return textureData; /** * For a given x/y, search the index for the closest line segment and return * its signed distance. Negative = inside, positive = outside, zero = on edge * @param x * @param y * @returns {number} */ function findNearestSignedDistance(x, y) { var closestDistSq = Infinity; var closestDist = Infinity; for (var i = segments.length; i--;) { var seg = segments[i]; if (seg.maxX + closestDist <= x) break; if (x + closestDist > seg.minX && y - closestDist < seg.maxY && y + closestDist > seg.minY) { var distSq = absSquareDistanceToLineSegment(x, y, seg.x1, seg.y1, seg.x2, seg.y2); if (distSq < closestDistSq) { closestDistSq = distSq; closestDist = Math.sqrt(closestDistSq); } } } if (isPointInPoly(x, y)) closestDist = -closestDist; return closestDist; } /** * Determine whether the given point lies inside or outside the glyph. Uses a simple * winding-number ray casting algorithm using a ray pointing east from the point. */ function isPointInPoly(x, y) { var winding = 0; for (var i = segments.length; i--;) { var seg = segments[i]; if (seg.maxX <= x) break; if (seg.y1 > y !== seg.y2 > y && x < (seg.x2 - seg.x1) * (y - seg.y1) / (seg.y2 - seg.y1) + seg.x1) winding += seg.y1 < seg.y2 ? 1 : -1; } return winding !== 0; } } function generateIntoCanvas$2(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent, canvas, x, y, channel) { if (sdfExponent === void 0) sdfExponent = 1; if (x === void 0) x = 0; if (y === void 0) y = 0; if (channel === void 0) channel = 0; generateIntoFramebuffer$1(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent, canvas, null, x, y, channel); } function generateIntoFramebuffer$1(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent, glOrCanvas, framebuffer, x, y, channel) { if (sdfExponent === void 0) sdfExponent = 1; if (x === void 0) x = 0; if (y === void 0) y = 0; if (channel === void 0) channel = 0; var data = generate$2(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent); var rgbaData = new Uint8Array(data.length * 4); for (var i = 0; i < data.length; i++) rgbaData[i * 4 + channel] = data[i]; renderImageData(glOrCanvas, rgbaData, x, y, sdfWidth, sdfHeight, 1 << 3 - channel, framebuffer); } /** * Find the absolute distance from a point to a line segment at closest approach */ function absSquareDistanceToLineSegment(x, y, lineX0, lineY0, lineX1, lineY1) { var ldx = lineX1 - lineX0; var ldy = lineY1 - lineY0; var lengthSq = ldx * ldx + ldy * ldy; var t = lengthSq ? Math.max(0, Math.min(1, ((x - lineX0) * ldx + (y - lineY0) * ldy) / lengthSq)) : 0; var dx = x - (lineX0 + t * ldx); var dy = y - (lineY0 + t * ldy); return dx * dx + dy * dy; } var javascript = /*#__PURE__*/ Object.freeze({ __proto__: null, generate: generate$2, generateIntoCanvas: generateIntoCanvas$2, generateIntoFramebuffer: generateIntoFramebuffer$1 }); var mainVertex = "precision highp float;uniform vec4 uGlyphBounds;attribute vec2 aUV;attribute vec4 aLineSegment;varying vec4 vLineSegment;varying vec2 vGlyphXY;void main(){vLineSegment=aLineSegment;vGlyphXY=mix(uGlyphBounds.xy,uGlyphBounds.zw,aUV);gl_Position=vec4(mix(vec2(-1.0),vec2(1.0),aUV),0.0,1.0);}"; var mainFragment = "precision highp float;uniform vec4 uGlyphBounds;uniform float uMaxDistance;uniform float uExponent;varying vec4 vLineSegment;varying vec2 vGlyphXY;float absDistToSegment(vec2 point,vec2 lineA,vec2 lineB){vec2 lineDir=lineB-lineA;float lenSq=dot(lineDir,lineDir);float t=lenSq==0.0 ? 0.0 : clamp(dot(point-lineA,lineDir)/lenSq,0.0,1.0);vec2 linePt=lineA+t*lineDir;return distance(point,linePt);}void main(){vec4 seg=vLineSegment;vec2 p=vGlyphXY;float dist=absDistToSegment(p,seg.xy,seg.zw);float val=pow(1.0-clamp(dist/uMaxDistance,0.0,1.0),uExponent)*0.5;bool crossing=(seg.y>p.y!=seg.w>p.y)&&(p.x<(seg.z-seg.x)*(p.y-seg.y)/(seg.w-seg.y)+seg.x);bool crossingUp=crossing&&vLineSegment.yCPU -- the `canvas` can be used directly as a WebGL texture image, so it all stays on the GPU. * * @param {number} sdfWidth - width of the SDF output image in pixels. * @param {number} sdfHeight - height of the SDF output image in pixels. * @param {string} path - an SVG-like path string describing the glyph; should only contain commands: M/L/Q/C/Z. * @param {number[]} viewBox - [minX, minY, maxX, maxY] in font units aligning with the texture's edges. * @param {number} maxDistance - the maximum distance from the glyph path in font units that will be encoded; defaults * to half the maximum viewBox dimension. * @param {number} [sdfExponent] - specifies an exponent for encoding the SDF's distance values; higher exponents * will give greater precision nearer the glyph's path. * @param {HTMLCanvasElement|OffscreenCanvas} canvas - a WebGL-enabled canvas into which the SDF will be rendered. * Only the relevant rect/channel will be modified, the rest will be preserved. To avoid unpredictable results * due to shared GL context state, this canvas should be dedicated to use by this library alone. * @param {number} x - the x position at which to render the SDF. * @param {number} y - the y position at which to render the SDF. * @param {number} channel - the color channel index (0-4) into which the SDF will be rendered. * @return {Uint8Array} */ function generateIntoCanvas(sdfWidth, sdfHeight, path, viewBox, maxDistance, sdfExponent, canvas, x, y, channel) { if (maxDistance === void 0) maxDistance = Math.max(viewBox[2] - viewBox[0], viewBox[3] - viewBox[1]) / 2; if (sdfExponent === void 0) sdfExponent = 1; if (x === void 0) x = 0; if (y === void 0) y = 0; if (channel === void 0) channel = 0; try { return generateIntoCanvas$1.apply(webgl, arguments); } catch (e) { console.info("WebGL SDF generation failed, falling back to JS", e); return generateIntoCanvas$2.apply(javascript, arguments); } } exports.forEachPathCommand = forEachPathCommand; exports.generate = generate; exports.generateIntoCanvas = generateIntoCanvas; exports.javascript = javascript; exports.pathToLineSegments = pathToLineSegments; exports.webgl = webgl; exports.webglUtils = webglUtils; Object.defineProperty(exports, "__esModule", { value: true }); return exports; }({}); } //#endregion //#region node_modules/bidi-js/dist/bidi.mjs function bidiFactory() { return function(exports) { var DATA = { "R": "13k,1a,2,3,3,2+1j,ch+16,a+1,5+2,2+n,5,a,4,6+16,4+3,h+1b,4mo,179q,2+9,2+11,2i9+7y,2+68,4,3+4,5+13,4+3,2+4k,3+29,8+cf,1t+7z,w+17,3+3m,1t+3z,16o1+5r,8+30,8+mc,29+1r,29+4v,75+73", "EN": "1c+9,3d+1,6,187+9,513,4+5,7+9,sf+j,175h+9,qw+q,161f+1d,4xt+a,25i+9", "ES": "17,2,6dp+1,f+1,av,16vr,mx+1,4o,2", "ET": "z+2,3h+3,b+1,ym,3e+1,2o,p4+1,8,6u,7c,g6,1wc,1n9+4,30+1b,2n,6d,qhx+1,h0m,a+1,49+2,63+1,4+1,6bb+3,12jj", "AN": "16o+5,2j+9,2+1,35,ed,1ff2+9,87+u", "CS": "18,2+1,b,2u,12k,55v,l,17v0,2,3,53,2+1,b", "B": "a,3,f+2,2v,690", "S": "9,2,k", "WS": "c,k,4f4,1vk+a,u,1j,335", "ON": "x+1,4+4,h+5,r+5,r+3,z,5+3,2+1,2+1,5,2+2,3+4,o,w,ci+1,8+d,3+d,6+8,2+g,39+1,9,6+1,2,33,b8,3+1,3c+1,7+1,5r,b,7h+3,sa+5,2,3i+6,jg+3,ur+9,2v,ij+1,9g+9,7+a,8m,4+1,49+x,14u,2+2,c+2,e+2,e+2,e+1,i+n,e+e,2+p,u+2,e+2,36+1,2+3,2+1,b,2+2,6+5,2,2,2,h+1,5+4,6+3,3+f,16+2,5+3l,3+81,1y+p,2+40,q+a,m+13,2r+ch,2+9e,75+hf,3+v,2+2w,6e+5,f+6,75+2a,1a+p,2+2g,d+5x,r+b,6+3,4+o,g,6+1,6+2,2k+1,4,2j,5h+z,1m+1,1e+f,t+2,1f+e,d+3,4o+3,2s+1,w,535+1r,h3l+1i,93+2,2s,b+1,3l+x,2v,4g+3,21+3,kz+1,g5v+1,5a,j+9,n+v,2,3,2+8,2+1,3+2,2,3,46+1,4+4,h+5,r+5,r+a,3h+2,4+6,b+4,78,1r+24,4+c,4,1hb,ey+6,103+j,16j+c,1ux+7,5+g,fsh,jdq+1t,4,57+2e,p1,1m,1m,1m,1m,4kt+1,7j+17,5+2r,d+e,3+e,2+e,2+10,m+4,w,1n+5,1q,4z+5,4b+rb,9+c,4+c,4+37,d+2g,8+b,l+b,5+1j,9+9,7+13,9+t,3+1,27+3c,2+29,2+3q,d+d,3+4,4+2,6+6,a+o,8+6,a+2,e+6,16+42,2+1i", "BN": "0+8,6+d,2s+5,2+p,e,4m9,1kt+2,2b+5,5+5,17q9+v,7k,6p+8,6+1,119d+3,440+7,96s+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+1,1ekf+75,6p+2rz,1ben+1,1ekf+1,1ekf+1", "NSM": "lc+33,7o+6,7c+18,2,2+1,2+1,2,21+a,1d+k,h,2u+6,3+5,3+1,2+3,10,v+q,2k+a,1n+8,a,p+3,2+8,2+2,2+4,18+2,3c+e,2+v,1k,2,5+7,5,4+6,b+1,u,1n,5+3,9,l+1,r,3+1,1m,5+1,5+1,3+2,4,v+1,4,c+1,1m,5+4,2+1,5,l+1,n+5,2,1n,3,2+3,9,8+1,c+1,v,1q,d,1f,4,1m+2,6+2,2+3,8+1,c+1,u,1n,g+1,l+1,t+1,1m+1,5+3,9,l+1,u,21,8+2,2,2j,3+6,d+7,2r,3+8,c+5,23+1,s,2,2,1k+d,2+4,2+1,6+a,2+z,a,2v+3,2+5,2+1,3+1,q+1,5+2,h+3,e,3+1,7,g,jk+2,qb+2,u+2,u+1,v+1,1t+1,2+6,9,3+a,a,1a+2,3c+1,z,3b+2,5+1,a,7+2,64+1,3,1n,2+6,2,2,3+7,7+9,3,1d+g,1s+3,1d,2+4,2,6,15+8,d+1,x+3,3+1,2+2,1l,2+1,4,2+2,1n+7,3+1,49+2,2+c,2+6,5,7,4+1,5j+1l,2+4,k1+w,2db+2,3y,2p+v,ff+3,30+1,n9x+3,2+9,x+1,29+1,7l,4,5,q+1,6,48+1,r+h,e,13+7,q+a,1b+2,1d,3+3,3+1,14,1w+5,3+1,3+1,d,9,1c,1g,2+2,3+1,6+1,2,17+1,9,6n,3,5,fn5,ki+f,h+f,r2,6b,46+4,1af+2,2+1,6+3,15+2,5,4m+1,fy+3,as+1,4a+a,4x,1j+e,1l+2,1e+3,3+1,1y+2,11+4,2+7,1r,d+1,1h+8,b+3,3,2o+2,3,2+1,7,4h,4+7,m+1,1m+1,4,12+6,4+4,5g+7,3+2,2,o,2d+5,2,5+1,2+1,6n+3,7+1,2+1,s+1,2e+7,3,2+1,2z,2,3+5,2,2u+2,3+3,2+4,78+8,2+1,75+1,2,5,41+3,3+1,5,x+5,3+1,15+5,3+3,9,a+5,3+2,1b+c,2+1,bb+6,2+5,2d+l,3+6,2+1,2+1,3f+5,4,2+1,2+6,2,21+1,4,2,9o+1,f0c+4,1o+6,t5,1s+3,2a,f5l+1,43t+2,i+7,3+6,v+3,45+2,1j0+1i,5+1d,9,f,n+4,2+e,11t+6,2+g,3+6,2+1,2+4,7a+6,c6+3,15t+6,32+6,gzhy+6n", "AL": "16w,3,2,e+1b,z+2,2+2s,g+1,8+1,b+m,2+t,s+2i,c+e,4h+f,1d+1e,1bwe+dp,3+3z,x+c,2+1,35+3y,2rm+z,5+7,b+5,dt+l,c+u,17nl+27,1t+27,4x+6n,3+d", "LRO": "6ct", "RLO": "6cu", "LRE": "6cq", "RLE": "6cr", "PDF": "6cs", "LRI": "6ee", "RLI": "6ef", "FSI": "6eg", "PDI": "6eh" }; var TYPES = {}; var TYPES_TO_NAMES = {}; TYPES.L = 1; TYPES_TO_NAMES[1] = "L"; Object.keys(DATA).forEach(function(type, i) { TYPES[type] = 1 << i + 1; TYPES_TO_NAMES[TYPES[type]] = type; }); Object.freeze(TYPES); var ISOLATE_INIT_TYPES = TYPES.LRI | TYPES.RLI | TYPES.FSI; var STRONG_TYPES = TYPES.L | TYPES.R | TYPES.AL; var NEUTRAL_ISOLATE_TYPES = TYPES.B | TYPES.S | TYPES.WS | TYPES.ON | TYPES.FSI | TYPES.LRI | TYPES.RLI | TYPES.PDI; var BN_LIKE_TYPES = TYPES.BN | TYPES.RLE | TYPES.LRE | TYPES.RLO | TYPES.LRO | TYPES.PDF; var TRAILING_TYPES = TYPES.S | TYPES.WS | TYPES.B | ISOLATE_INIT_TYPES | TYPES.PDI | BN_LIKE_TYPES; var map = null; function parseData() { if (!map) { map = /* @__PURE__ */ new Map(); var loop = function(type) { if (DATA.hasOwnProperty(type)) { var lastCode = 0; DATA[type].split(",").forEach(function(range) { var ref = range.split("+"); var skip = ref[0]; var step = ref[1]; skip = parseInt(skip, 36); step = step ? parseInt(step, 36) : 0; map.set(lastCode += skip, TYPES[type]); for (var i = 0; i < step; i++) map.set(++lastCode, TYPES[type]); }); } }; for (var type in DATA) loop(type); } } /** * @param {string} char * @return {number} */ function getBidiCharType(char) { parseData(); return map.get(char.codePointAt(0)) || TYPES.L; } function getBidiCharTypeName(char) { return TYPES_TO_NAMES[getBidiCharType(char)]; } var data$1 = { "pairs": "14>1,1e>2,u>2,2wt>1,1>1,1ge>1,1wp>1,1j>1,f>1,hm>1,1>1,u>1,u6>1,1>1,+5,28>1,w>1,1>1,+3,b8>1,1>1,+3,1>3,-1>-1,3>1,1>1,+2,1s>1,1>1,x>1,th>1,1>1,+2,db>1,1>1,+3,3>1,1>1,+2,14qm>1,1>1,+1,4q>1,1e>2,u>2,2>1,+1", "canonical": "6f1>-6dx,6dy>-6dx,6ec>-6ed,6ee>-6ed,6ww>2jj,-2ji>2jj,14r4>-1e7l,1e7m>-1e7l,1e7m>-1e5c,1e5d>-1e5b,1e5c>-14qx,14qy>-14qx,14vn>-1ecg,1ech>-1ecg,1edu>-1ecg,1eci>-1ecg,1eda>-1ecg,1eci>-1ecg,1eci>-168q,168r>-168q,168s>-14ye,14yf>-14ye" }; /** * Parses an string that holds encoded codepoint mappings, e.g. for bracket pairs or * mirroring characters, as encoded by scripts/generateBidiData.js. Returns an object * holding the `map`, and optionally a `reverseMap` if `includeReverse:true`. * @param {string} encodedString * @param {boolean} includeReverse - true if you want reverseMap in the output * @return {{map: Map, reverseMap?: Map}} */ function parseCharacterMap(encodedString, includeReverse) { var radix = 36; var lastCode = 0; var map = /* @__PURE__ */ new Map(); var reverseMap = includeReverse && /* @__PURE__ */ new Map(); var prevPair; encodedString.split(",").forEach(function visit(entry) { if (entry.indexOf("+") !== -1) for (var i = +entry; i--;) visit(prevPair); else { prevPair = entry; var ref = entry.split(">"); var a = ref[0]; var b = ref[1]; a = String.fromCodePoint(lastCode += parseInt(a, radix)); b = String.fromCodePoint(lastCode += parseInt(b, radix)); map.set(a, b); includeReverse && reverseMap.set(b, a); } }); return { map, reverseMap }; } var openToClose, closeToOpen, canonical; function parse$1() { if (!openToClose) { var ref = parseCharacterMap(data$1.pairs, true); var map = ref.map; var reverseMap = ref.reverseMap; openToClose = map; closeToOpen = reverseMap; canonical = parseCharacterMap(data$1.canonical, false).map; } } function openingToClosingBracket(char) { parse$1(); return openToClose.get(char) || null; } function closingToOpeningBracket(char) { parse$1(); return closeToOpen.get(char) || null; } function getCanonicalBracket(char) { parse$1(); return canonical.get(char) || null; } var TYPE_L = TYPES.L; var TYPE_R = TYPES.R; var TYPE_EN = TYPES.EN; var TYPE_ES = TYPES.ES; var TYPE_ET = TYPES.ET; var TYPE_AN = TYPES.AN; var TYPE_CS = TYPES.CS; var TYPE_B = TYPES.B; var TYPE_S = TYPES.S; var TYPE_ON = TYPES.ON; var TYPE_BN = TYPES.BN; var TYPE_NSM = TYPES.NSM; var TYPE_AL = TYPES.AL; var TYPE_LRO = TYPES.LRO; var TYPE_RLO = TYPES.RLO; var TYPE_LRE = TYPES.LRE; var TYPE_RLE = TYPES.RLE; var TYPE_PDF = TYPES.PDF; var TYPE_LRI = TYPES.LRI; var TYPE_RLI = TYPES.RLI; var TYPE_FSI = TYPES.FSI; var TYPE_PDI = TYPES.PDI; /** * @typedef {object} GetEmbeddingLevelsResult * @property {{start, end, level}[]} paragraphs * @property {Uint8Array} levels */ /** * This function applies the Bidirectional Algorithm to a string, returning the resolved embedding levels * in a single Uint8Array plus a list of objects holding each paragraph's start and end indices and resolved * base embedding level. * * @param {string} string - The input string * @param {"ltr"|"rtl"|"auto"} [baseDirection] - Use "ltr" or "rtl" to force a base paragraph direction, * otherwise a direction will be chosen automatically from each paragraph's contents. * @return {GetEmbeddingLevelsResult} */ function getEmbeddingLevels(string, baseDirection) { var MAX_DEPTH = 125; var charTypes = new Uint32Array(string.length); for (var i = 0; i < string.length; i++) charTypes[i] = getBidiCharType(string[i]); var charTypeCounts = /* @__PURE__ */ new Map(); function changeCharType(i, type) { var oldType = charTypes[i]; charTypes[i] = type; charTypeCounts.set(oldType, charTypeCounts.get(oldType) - 1); if (oldType & NEUTRAL_ISOLATE_TYPES) charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) - 1); charTypeCounts.set(type, (charTypeCounts.get(type) || 0) + 1); if (type & NEUTRAL_ISOLATE_TYPES) charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) || 0) + 1); } var embedLevels = new Uint8Array(string.length); var isolationPairs = /* @__PURE__ */ new Map(); var paragraphs = []; var paragraph = null; for (var i$1 = 0; i$1 < string.length; i$1++) { if (!paragraph) paragraphs.push(paragraph = { start: i$1, end: string.length - 1, level: baseDirection === "rtl" ? 1 : baseDirection === "ltr" ? 0 : determineAutoEmbedLevel(i$1, false) }); if (charTypes[i$1] & TYPE_B) { paragraph.end = i$1; paragraph = null; } } var FORMATTING_TYPES = TYPE_RLE | TYPE_LRE | TYPE_RLO | TYPE_LRO | ISOLATE_INIT_TYPES | TYPE_PDI | TYPE_PDF | TYPE_B; var nextEven = function(n) { return n + (n & 1 ? 1 : 2); }; var nextOdd = function(n) { return n + (n & 1 ? 2 : 1); }; for (var paraIdx = 0; paraIdx < paragraphs.length; paraIdx++) { paragraph = paragraphs[paraIdx]; var statusStack = [{ _level: paragraph.level, _override: 0, _isolate: 0 }]; var stackTop = void 0; var overflowIsolateCount = 0; var overflowEmbeddingCount = 0; var validIsolateCount = 0; charTypeCounts.clear(); for (var i$2 = paragraph.start; i$2 <= paragraph.end; i$2++) { var charType = charTypes[i$2]; stackTop = statusStack[statusStack.length - 1]; charTypeCounts.set(charType, (charTypeCounts.get(charType) || 0) + 1); if (charType & NEUTRAL_ISOLATE_TYPES) charTypeCounts.set(NEUTRAL_ISOLATE_TYPES, (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES) || 0) + 1); if (charType & FORMATTING_TYPES) { if (charType & (TYPE_RLE | TYPE_LRE)) { embedLevels[i$2] = stackTop._level; var level = (charType === TYPE_RLE ? nextOdd : nextEven)(stackTop._level); if (level <= MAX_DEPTH && !overflowIsolateCount && !overflowEmbeddingCount) statusStack.push({ _level: level, _override: 0, _isolate: 0 }); else if (!overflowIsolateCount) overflowEmbeddingCount++; } else if (charType & (TYPE_RLO | TYPE_LRO)) { embedLevels[i$2] = stackTop._level; var level$1 = (charType === TYPE_RLO ? nextOdd : nextEven)(stackTop._level); if (level$1 <= MAX_DEPTH && !overflowIsolateCount && !overflowEmbeddingCount) statusStack.push({ _level: level$1, _override: charType & TYPE_RLO ? TYPE_R : TYPE_L, _isolate: 0 }); else if (!overflowIsolateCount) overflowEmbeddingCount++; } else if (charType & ISOLATE_INIT_TYPES) { if (charType & TYPE_FSI) charType = determineAutoEmbedLevel(i$2 + 1, true) === 1 ? TYPE_RLI : TYPE_LRI; embedLevels[i$2] = stackTop._level; if (stackTop._override) changeCharType(i$2, stackTop._override); var level$2 = (charType === TYPE_RLI ? nextOdd : nextEven)(stackTop._level); if (level$2 <= MAX_DEPTH && overflowIsolateCount === 0 && overflowEmbeddingCount === 0) { validIsolateCount++; statusStack.push({ _level: level$2, _override: 0, _isolate: 1, _isolInitIndex: i$2 }); } else overflowIsolateCount++; } else if (charType & TYPE_PDI) { if (overflowIsolateCount > 0) overflowIsolateCount--; else if (validIsolateCount > 0) { overflowEmbeddingCount = 0; while (!statusStack[statusStack.length - 1]._isolate) statusStack.pop(); var isolInitIndex = statusStack[statusStack.length - 1]._isolInitIndex; if (isolInitIndex != null) { isolationPairs.set(isolInitIndex, i$2); isolationPairs.set(i$2, isolInitIndex); } statusStack.pop(); validIsolateCount--; } stackTop = statusStack[statusStack.length - 1]; embedLevels[i$2] = stackTop._level; if (stackTop._override) changeCharType(i$2, stackTop._override); } else if (charType & TYPE_PDF) { if (overflowIsolateCount === 0) { if (overflowEmbeddingCount > 0) overflowEmbeddingCount--; else if (!stackTop._isolate && statusStack.length > 1) { statusStack.pop(); stackTop = statusStack[statusStack.length - 1]; } } embedLevels[i$2] = stackTop._level; } else if (charType & TYPE_B) embedLevels[i$2] = paragraph.level; } else { embedLevels[i$2] = stackTop._level; if (stackTop._override && charType !== TYPE_BN) changeCharType(i$2, stackTop._override); } } var levelRuns = []; var currentRun = null; for (var i$3 = paragraph.start; i$3 <= paragraph.end; i$3++) { var charType$1 = charTypes[i$3]; if (!(charType$1 & BN_LIKE_TYPES)) { var lvl = embedLevels[i$3]; var isIsolInit = charType$1 & ISOLATE_INIT_TYPES; var isPDI = charType$1 === TYPE_PDI; if (currentRun && lvl === currentRun._level) { currentRun._end = i$3; currentRun._endsWithIsolInit = isIsolInit; } else levelRuns.push(currentRun = { _start: i$3, _end: i$3, _level: lvl, _startsWithPDI: isPDI, _endsWithIsolInit: isIsolInit }); } } var isolatingRunSeqs = []; for (var runIdx = 0; runIdx < levelRuns.length; runIdx++) { var run = levelRuns[runIdx]; if (!run._startsWithPDI || run._startsWithPDI && !isolationPairs.has(run._start)) { var seqRuns = [currentRun = run]; for (var pdiIndex = void 0; currentRun && currentRun._endsWithIsolInit && (pdiIndex = isolationPairs.get(currentRun._end)) != null;) for (var i$4 = runIdx + 1; i$4 < levelRuns.length; i$4++) if (levelRuns[i$4]._start === pdiIndex) { seqRuns.push(currentRun = levelRuns[i$4]); break; } var seqIndices = []; for (var i$5 = 0; i$5 < seqRuns.length; i$5++) { var run$1 = seqRuns[i$5]; for (var j = run$1._start; j <= run$1._end; j++) seqIndices.push(j); } var firstLevel = embedLevels[seqIndices[0]]; var prevLevel = paragraph.level; for (var i$6 = seqIndices[0] - 1; i$6 >= 0; i$6--) if (!(charTypes[i$6] & BN_LIKE_TYPES)) { prevLevel = embedLevels[i$6]; break; } var lastIndex = seqIndices[seqIndices.length - 1]; var lastLevel = embedLevels[lastIndex]; var nextLevel = paragraph.level; if (!(charTypes[lastIndex] & ISOLATE_INIT_TYPES)) { for (var i$7 = lastIndex + 1; i$7 <= paragraph.end; i$7++) if (!(charTypes[i$7] & BN_LIKE_TYPES)) { nextLevel = embedLevels[i$7]; break; } } isolatingRunSeqs.push({ _seqIndices: seqIndices, _sosType: Math.max(prevLevel, firstLevel) % 2 ? TYPE_R : TYPE_L, _eosType: Math.max(nextLevel, lastLevel) % 2 ? TYPE_R : TYPE_L }); } } for (var seqIdx = 0; seqIdx < isolatingRunSeqs.length; seqIdx++) { var ref = isolatingRunSeqs[seqIdx]; var seqIndices$1 = ref._seqIndices; var sosType = ref._sosType; var eosType = ref._eosType; /** * All the level runs in an isolating run sequence have the same embedding level. * * DO NOT change any `embedLevels[i]` within the current scope. */ var embedDirection = embedLevels[seqIndices$1[0]] & 1 ? TYPE_R : TYPE_L; if (charTypeCounts.get(TYPE_NSM)) for (var si = 0; si < seqIndices$1.length; si++) { var i$8 = seqIndices$1[si]; if (charTypes[i$8] & TYPE_NSM) { var prevType = sosType; for (var sj = si - 1; sj >= 0; sj--) if (!(charTypes[seqIndices$1[sj]] & BN_LIKE_TYPES)) { prevType = charTypes[seqIndices$1[sj]]; break; } changeCharType(i$8, prevType & (ISOLATE_INIT_TYPES | TYPE_PDI) ? TYPE_ON : prevType); } } if (charTypeCounts.get(TYPE_EN)) for (var si$1 = 0; si$1 < seqIndices$1.length; si$1++) { var i$9 = seqIndices$1[si$1]; if (charTypes[i$9] & TYPE_EN) for (var sj$1 = si$1 - 1; sj$1 >= -1; sj$1--) { var prevCharType = sj$1 === -1 ? sosType : charTypes[seqIndices$1[sj$1]]; if (prevCharType & STRONG_TYPES) { if (prevCharType === TYPE_AL) changeCharType(i$9, TYPE_AN); break; } } } if (charTypeCounts.get(TYPE_AL)) for (var si$2 = 0; si$2 < seqIndices$1.length; si$2++) { var i$10 = seqIndices$1[si$2]; if (charTypes[i$10] & TYPE_AL) changeCharType(i$10, TYPE_R); } if (charTypeCounts.get(TYPE_ES) || charTypeCounts.get(TYPE_CS)) for (var si$3 = 1; si$3 < seqIndices$1.length - 1; si$3++) { var i$11 = seqIndices$1[si$3]; if (charTypes[i$11] & (TYPE_ES | TYPE_CS)) { var prevType$1 = 0, nextType = 0; for (var sj$2 = si$3 - 1; sj$2 >= 0; sj$2--) { prevType$1 = charTypes[seqIndices$1[sj$2]]; if (!(prevType$1 & BN_LIKE_TYPES)) break; } for (var sj$3 = si$3 + 1; sj$3 < seqIndices$1.length; sj$3++) { nextType = charTypes[seqIndices$1[sj$3]]; if (!(nextType & BN_LIKE_TYPES)) break; } if (prevType$1 === nextType && (charTypes[i$11] === TYPE_ES ? prevType$1 === TYPE_EN : prevType$1 & (TYPE_EN | TYPE_AN))) changeCharType(i$11, prevType$1); } } if (charTypeCounts.get(TYPE_EN)) { for (var si$4 = 0; si$4 < seqIndices$1.length; si$4++) if (charTypes[seqIndices$1[si$4]] & TYPE_EN) { for (var sj$4 = si$4 - 1; sj$4 >= 0 && charTypes[seqIndices$1[sj$4]] & (TYPE_ET | BN_LIKE_TYPES); sj$4--) changeCharType(seqIndices$1[sj$4], TYPE_EN); for (si$4++; si$4 < seqIndices$1.length && charTypes[seqIndices$1[si$4]] & (TYPE_ET | BN_LIKE_TYPES | TYPE_EN); si$4++) if (charTypes[seqIndices$1[si$4]] !== TYPE_EN) changeCharType(seqIndices$1[si$4], TYPE_EN); } } if (charTypeCounts.get(TYPE_ET) || charTypeCounts.get(TYPE_ES) || charTypeCounts.get(TYPE_CS)) for (var si$5 = 0; si$5 < seqIndices$1.length; si$5++) { var i$13 = seqIndices$1[si$5]; if (charTypes[i$13] & (TYPE_ET | TYPE_ES | TYPE_CS)) { changeCharType(i$13, TYPE_ON); for (var sj$5 = si$5 - 1; sj$5 >= 0 && charTypes[seqIndices$1[sj$5]] & BN_LIKE_TYPES; sj$5--) changeCharType(seqIndices$1[sj$5], TYPE_ON); for (var sj$6 = si$5 + 1; sj$6 < seqIndices$1.length && charTypes[seqIndices$1[sj$6]] & BN_LIKE_TYPES; sj$6++) changeCharType(seqIndices$1[sj$6], TYPE_ON); } } if (charTypeCounts.get(TYPE_EN)) for (var si$6 = 0, prevStrongType = sosType; si$6 < seqIndices$1.length; si$6++) { var i$14 = seqIndices$1[si$6]; var type = charTypes[i$14]; if (type & TYPE_EN) { if (prevStrongType === TYPE_L) changeCharType(i$14, TYPE_L); } else if (type & STRONG_TYPES) prevStrongType = type; } if (charTypeCounts.get(NEUTRAL_ISOLATE_TYPES)) { var R_TYPES_FOR_N_STEPS = TYPE_R | TYPE_EN | TYPE_AN; var STRONG_TYPES_FOR_N_STEPS = R_TYPES_FOR_N_STEPS | TYPE_L; var bracketPairs = []; var openerStack = []; for (var si$7 = 0; si$7 < seqIndices$1.length; si$7++) if (charTypes[seqIndices$1[si$7]] & NEUTRAL_ISOLATE_TYPES) { var char = string[seqIndices$1[si$7]]; var oppositeBracket = void 0; if (openingToClosingBracket(char) !== null) if (openerStack.length < 63) openerStack.push({ char, seqIndex: si$7 }); else break; else if ((oppositeBracket = closingToOpeningBracket(char)) !== null) for (var stackIdx = openerStack.length - 1; stackIdx >= 0; stackIdx--) { var stackChar = openerStack[stackIdx].char; if (stackChar === oppositeBracket || stackChar === closingToOpeningBracket(getCanonicalBracket(char)) || openingToClosingBracket(getCanonicalBracket(stackChar)) === char) { bracketPairs.push([openerStack[stackIdx].seqIndex, si$7]); openerStack.length = stackIdx; break; } } } bracketPairs.sort(function(a, b) { return a[0] - b[0]; }); for (var pairIdx = 0; pairIdx < bracketPairs.length; pairIdx++) { var ref$1 = bracketPairs[pairIdx]; var openSeqIdx = ref$1[0]; var closeSeqIdx = ref$1[1]; var foundStrongType = false; var useStrongType = 0; for (var si$8 = openSeqIdx + 1; si$8 < closeSeqIdx; si$8++) { var i$15 = seqIndices$1[si$8]; if (charTypes[i$15] & STRONG_TYPES_FOR_N_STEPS) { foundStrongType = true; var lr = charTypes[i$15] & R_TYPES_FOR_N_STEPS ? TYPE_R : TYPE_L; if (lr === embedDirection) { useStrongType = lr; break; } } } if (foundStrongType && !useStrongType) { useStrongType = sosType; for (var si$9 = openSeqIdx - 1; si$9 >= 0; si$9--) { var i$16 = seqIndices$1[si$9]; if (charTypes[i$16] & STRONG_TYPES_FOR_N_STEPS) { var lr$1 = charTypes[i$16] & R_TYPES_FOR_N_STEPS ? TYPE_R : TYPE_L; if (lr$1 !== embedDirection) useStrongType = lr$1; else useStrongType = embedDirection; break; } } } if (useStrongType) { charTypes[seqIndices$1[openSeqIdx]] = charTypes[seqIndices$1[closeSeqIdx]] = useStrongType; if (useStrongType !== embedDirection) { for (var si$10 = openSeqIdx + 1; si$10 < seqIndices$1.length; si$10++) if (!(charTypes[seqIndices$1[si$10]] & BN_LIKE_TYPES)) { if (getBidiCharType(string[seqIndices$1[si$10]]) & TYPE_NSM) charTypes[seqIndices$1[si$10]] = useStrongType; break; } } if (useStrongType !== embedDirection) { for (var si$11 = closeSeqIdx + 1; si$11 < seqIndices$1.length; si$11++) if (!(charTypes[seqIndices$1[si$11]] & BN_LIKE_TYPES)) { if (getBidiCharType(string[seqIndices$1[si$11]]) & TYPE_NSM) charTypes[seqIndices$1[si$11]] = useStrongType; break; } } } } for (var si$12 = 0; si$12 < seqIndices$1.length; si$12++) if (charTypes[seqIndices$1[si$12]] & NEUTRAL_ISOLATE_TYPES) { var niRunStart = si$12, niRunEnd = si$12; var prevType$2 = sosType; for (var si2 = si$12 - 1; si2 >= 0; si2--) if (charTypes[seqIndices$1[si2]] & BN_LIKE_TYPES) niRunStart = si2; else { prevType$2 = charTypes[seqIndices$1[si2]] & R_TYPES_FOR_N_STEPS ? TYPE_R : TYPE_L; break; } var nextType$1 = eosType; for (var si2$1 = si$12 + 1; si2$1 < seqIndices$1.length; si2$1++) if (charTypes[seqIndices$1[si2$1]] & (NEUTRAL_ISOLATE_TYPES | BN_LIKE_TYPES)) niRunEnd = si2$1; else { nextType$1 = charTypes[seqIndices$1[si2$1]] & R_TYPES_FOR_N_STEPS ? TYPE_R : TYPE_L; break; } for (var sj$7 = niRunStart; sj$7 <= niRunEnd; sj$7++) charTypes[seqIndices$1[sj$7]] = prevType$2 === nextType$1 ? prevType$2 : embedDirection; si$12 = niRunEnd; } } } for (var i$17 = paragraph.start; i$17 <= paragraph.end; i$17++) { var level$3 = embedLevels[i$17]; var type$1 = charTypes[i$17]; if (level$3 & 1) { if (type$1 & (TYPE_L | TYPE_EN | TYPE_AN)) embedLevels[i$17]++; } else if (type$1 & TYPE_R) embedLevels[i$17]++; else if (type$1 & (TYPE_AN | TYPE_EN)) embedLevels[i$17] += 2; if (type$1 & BN_LIKE_TYPES) embedLevels[i$17] = i$17 === 0 ? paragraph.level : embedLevels[i$17 - 1]; if (i$17 === paragraph.end || getBidiCharType(string[i$17]) & (TYPE_S | TYPE_B)) for (var j$1 = i$17; j$1 >= 0 && getBidiCharType(string[j$1]) & TRAILING_TYPES; j$1--) embedLevels[j$1] = paragraph.level; } } return { levels: embedLevels, paragraphs }; function determineAutoEmbedLevel(start, isFSI) { for (var i = start; i < string.length; i++) { var charType = charTypes[i]; if (charType & (TYPE_R | TYPE_AL)) return 1; if (charType & (TYPE_B | TYPE_L) || isFSI && charType === TYPE_PDI) return 0; if (charType & ISOLATE_INIT_TYPES) { var pdi = indexOfMatchingPDI(i); i = pdi === -1 ? string.length : pdi; } } return 0; } function indexOfMatchingPDI(isolateStart) { var isolationLevel = 1; for (var i = isolateStart + 1; i < string.length; i++) { var charType = charTypes[i]; if (charType & TYPE_B) break; if (charType & TYPE_PDI) { if (--isolationLevel === 0) return i; } else if (charType & ISOLATE_INIT_TYPES) isolationLevel++; } return -1; } } var data = "14>1,j>2,t>2,u>2,1a>g,2v3>1,1>1,1ge>1,1wd>1,b>1,1j>1,f>1,ai>3,-2>3,+1,8>1k0,-1jq>1y7,-1y6>1hf,-1he>1h6,-1h5>1ha,-1h8>1qi,-1pu>1,6>3u,-3s>7,6>1,1>1,f>1,1>1,+2,3>1,1>1,+13,4>1,1>1,6>1eo,-1ee>1,3>1mg,-1me>1mk,-1mj>1mi,-1mg>1mi,-1md>1,1>1,+2,1>10k,-103>1,1>1,4>1,5>1,1>1,+10,3>1,1>8,-7>8,+1,-6>7,+1,a>1,1>1,u>1,u6>1,1>1,+5,26>1,1>1,2>1,2>2,8>1,7>1,4>1,1>1,+5,b8>1,1>1,+3,1>3,-2>1,2>1,1>1,+2,c>1,3>1,1>1,+2,h>1,3>1,a>1,1>1,2>1,3>1,1>1,d>1,f>1,3>1,1a>1,1>1,6>1,7>1,13>1,k>1,1>1,+19,4>1,1>1,+2,2>1,1>1,+18,m>1,a>1,1>1,lk>1,1>1,4>1,2>1,f>1,3>1,1>1,+3,db>1,1>1,+3,3>1,1>1,+2,14qm>1,1>1,+1,6>1,4j>1,j>2,t>2,u>2,2>1,+1"; var mirrorMap; function parse() { if (!mirrorMap) { var ref = parseCharacterMap(data, true); var map = ref.map; ref.reverseMap.forEach(function(value, key) { map.set(key, value); }); mirrorMap = map; } } function getMirroredCharacter(char) { parse(); return mirrorMap.get(char) || null; } /** * Given a string and its resolved embedding levels, build a map of indices to replacement chars * for any characters in right-to-left segments that have defined mirrored characters. * @param string * @param embeddingLevels * @param [start] * @param [end] * @return {Map} */ function getMirroredCharactersMap(string, embeddingLevels, start, end) { var strLen = string.length; start = Math.max(0, start == null ? 0 : +start); end = Math.min(strLen - 1, end == null ? strLen - 1 : +end); var map = /* @__PURE__ */ new Map(); for (var i = start; i <= end; i++) if (embeddingLevels[i] & 1) { var mirror = getMirroredCharacter(string[i]); if (mirror !== null) map.set(i, mirror); } return map; } /** * Given a start and end denoting a single line within a string, and a set of precalculated * bidi embedding levels, produce a list of segments whose ordering should be flipped, in sequence. * @param {string} string - the full input string * @param {GetEmbeddingLevelsResult} embeddingLevelsResult - the result object from getEmbeddingLevels * @param {number} [start] - first character in a subset of the full string * @param {number} [end] - last character in a subset of the full string * @return {number[][]} - the list of start/end segments that should be flipped, in order. */ function getReorderSegments(string, embeddingLevelsResult, start, end) { var strLen = string.length; start = Math.max(0, start == null ? 0 : +start); end = Math.min(strLen - 1, end == null ? strLen - 1 : +end); var segments = []; embeddingLevelsResult.paragraphs.forEach(function(paragraph) { var lineStart = Math.max(start, paragraph.start); var lineEnd = Math.min(end, paragraph.end); if (lineStart < lineEnd) { var lineLevels = embeddingLevelsResult.levels.slice(lineStart, lineEnd + 1); for (var i = lineEnd; i >= lineStart && getBidiCharType(string[i]) & TRAILING_TYPES; i--) lineLevels[i] = paragraph.level; var maxLevel = paragraph.level; var minOddLevel = Infinity; for (var i$1 = 0; i$1 < lineLevels.length; i$1++) { var level = lineLevels[i$1]; if (level > maxLevel) maxLevel = level; if (level < minOddLevel) minOddLevel = level | 1; } for (var lvl = maxLevel; lvl >= minOddLevel; lvl--) for (var i$2 = 0; i$2 < lineLevels.length; i$2++) if (lineLevels[i$2] >= lvl) { var segStart = i$2; while (i$2 + 1 < lineLevels.length && lineLevels[i$2 + 1] >= lvl) i$2++; if (i$2 > segStart) segments.push([segStart + lineStart, i$2 + lineStart]); } } }); return segments; } /** * @param {string} string * @param {GetEmbeddingLevelsResult} embedLevelsResult * @param {number} [start] * @param {number} [end] * @return {string} the new string with bidi segments reordered */ function getReorderedString(string, embedLevelsResult, start, end) { var indices = getReorderedIndices(string, embedLevelsResult, start, end); var chars = [].concat(string); indices.forEach(function(charIndex, i) { chars[i] = (embedLevelsResult.levels[charIndex] & 1 ? getMirroredCharacter(string[charIndex]) : null) || string[charIndex]; }); return chars.join(""); } /** * @param {string} string * @param {GetEmbeddingLevelsResult} embedLevelsResult * @param {number} [start] * @param {number} [end] * @return {number[]} an array with character indices in their new bidi order */ function getReorderedIndices(string, embedLevelsResult, start, end) { var segments = getReorderSegments(string, embedLevelsResult, start, end); var indices = []; for (var i = 0; i < string.length; i++) indices[i] = i; segments.forEach(function(ref) { var start = ref[0]; var end = ref[1]; var slice = indices.slice(start, end + 1); for (var i = slice.length; i--;) indices[end - i] = slice[i]; }); return indices; } exports.closingToOpeningBracket = closingToOpeningBracket; exports.getBidiCharType = getBidiCharType; exports.getBidiCharTypeName = getBidiCharTypeName; exports.getCanonicalBracket = getCanonicalBracket; exports.getEmbeddingLevels = getEmbeddingLevels; exports.getMirroredCharacter = getMirroredCharacter; exports.getMirroredCharactersMap = getMirroredCharactersMap; exports.getReorderSegments = getReorderSegments; exports.getReorderedIndices = getReorderedIndices; exports.getReorderedString = getReorderedString; exports.openingToClosingBracket = openingToClosingBracket; Object.defineProperty(exports, "__esModule", { value: true }); return exports; }({}); } //#endregion //#region node_modules/troika-three-utils/dist/troika-three-utils.esm.js /** * Regular expression for matching the `void main() {` opener line in GLSL. * @type {RegExp} */ var voidMainRegExp = /\bvoid\s+main\s*\(\s*\)\s*{/g; /** * Recursively expands all `#include ` statements within string of shader code. * Copied from three's WebGLProgram#parseIncludes for external use. * * @param {string} source - The GLSL source code to evaluate * @return {string} The GLSL code with all includes expanded */ function expandShaderIncludes(source) { const pattern = /^[ \t]*#include +<([\w\d./]+)>/gm; function replace(match, include) { let chunk = ShaderChunk[include]; return chunk ? expandShaderIncludes(chunk) : match; } return source.replace(pattern, replace); } var _lut = []; for (let i = 0; i < 256; i++) _lut[i] = (i < 16 ? "0" : "") + i.toString(16); function generateUUID() { const d0 = Math.random() * 4294967295 | 0; const d1 = Math.random() * 4294967295 | 0; const d2 = Math.random() * 4294967295 | 0; const d3 = Math.random() * 4294967295 | 0; return (_lut[d0 & 255] + _lut[d0 >> 8 & 255] + _lut[d0 >> 16 & 255] + _lut[d0 >> 24 & 255] + "-" + _lut[d1 & 255] + _lut[d1 >> 8 & 255] + "-" + _lut[d1 >> 16 & 15 | 64] + _lut[d1 >> 24 & 255] + "-" + _lut[d2 & 63 | 128] + _lut[d2 >> 8 & 255] + "-" + _lut[d2 >> 16 & 255] + _lut[d2 >> 24 & 255] + _lut[d3 & 255] + _lut[d3 >> 8 & 255] + _lut[d3 >> 16 & 255] + _lut[d3 >> 24 & 255]).toUpperCase(); } var assign$1 = Object.assign || function() { let target = arguments[0]; for (let i = 1, len = arguments.length; i < len; i++) { let source = arguments[i]; if (source) { for (let prop in source) if (Object.prototype.hasOwnProperty.call(source, prop)) target[prop] = source[prop]; } } return target; }; var epoch = Date.now(); var CONSTRUCTOR_CACHE = /* @__PURE__ */ new WeakMap(); var SHADER_UPGRADE_CACHE = /* @__PURE__ */ new Map(); var materialInstanceId = 1e10; /** * A utility for creating a custom shader material derived from another material's * shaders. This allows you to inject custom shader logic and transforms into the * builtin ThreeJS materials without having to recreate them from scratch. * * @param {THREE.Material} baseMaterial - the original material to derive from * * @param {Object} options - How the base material should be modified. * @param {Object=} options.defines - Custom `defines` for the material * @param {Object=} options.extensions - Custom `extensions` for the material, e.g. `{derivatives: true}` * @param {Object=} options.uniforms - Custom `uniforms` for use in the modified shader. These can * be accessed and manipulated via the resulting material's `uniforms` property, just like * in a ShaderMaterial. You do not need to repeat the base material's own uniforms here. * @param {String=} options.timeUniform - If specified, a uniform of this name will be injected into * both shaders, and it will automatically be updated on each render frame with a number of * elapsed milliseconds. The "zero" epoch time is not significant so don't rely on this as a * true calendar time. * @param {String=} options.vertexDefs - Custom GLSL code to inject into the vertex shader's top-level * definitions, above the `void main()` function. * @param {String=} options.vertexMainIntro - Custom GLSL code to inject at the top of the vertex * shader's `void main` function. * @param {String=} options.vertexMainOutro - Custom GLSL code to inject at the end of the vertex * shader's `void main` function. * @param {String=} options.vertexTransform - Custom GLSL code to manipulate the `position`, `normal`, * and/or `uv` vertex attributes. This code will be wrapped within a standalone function with * those attributes exposed by their normal names as read/write values. * @param {String=} options.fragmentDefs - Custom GLSL code to inject into the fragment shader's top-level * definitions, above the `void main()` function. * @param {String=} options.fragmentMainIntro - Custom GLSL code to inject at the top of the fragment * shader's `void main` function. * @param {String=} options.fragmentMainOutro - Custom GLSL code to inject at the end of the fragment * shader's `void main` function. You can manipulate `gl_FragColor` here but keep in mind it goes * after any of ThreeJS's color postprocessing shader chunks (tonemapping, fog, etc.), so if you * want those to apply to your changes use `fragmentColorTransform` instead. * @param {String=} options.fragmentColorTransform - Custom GLSL code to manipulate the `gl_FragColor` * output value. Will be injected near the end of the `void main` function, but before any * of ThreeJS's color postprocessing shader chunks (tonemapping, fog, etc.), and before the * `fragmentMainOutro`. * @param {function({fragmentShader: string, vertexShader:string}): * {fragmentShader: string, vertexShader:string}} options.customRewriter - A function * for performing custom rewrites of the full shader code. Useful if you need to do something * special that's not covered by the other builtin options. This function will be executed before * any other transforms are applied. * @param {boolean=} options.chained - Set to `true` to prototype-chain the derived material to the base * material, rather than the default behavior of copying it. This allows the derived material to * automatically pick up changes made to the base material and its properties. This can be useful * where the derived material is hidden from the user as an implementation detail, allowing them * to work with the original material like normal. But it can result in unexpected behavior if not * handled carefully. * * @return {THREE.Material} * * The returned material will also have two new methods, `getDepthMaterial()` and `getDistanceMaterial()`, * which can be called to get a variant of the derived material for use in shadow casting. If the * target mesh is expected to cast shadows, then you can assign these to the mesh's `customDepthMaterial` * (for directional and spot lights) and/or `customDistanceMaterial` (for point lights) properties to * allow the cast shadow to honor your derived shader's vertex transforms and discarded fragments. These * will also set a custom `#define IS_DEPTH_MATERIAL` or `#define IS_DISTANCE_MATERIAL` that you can look * for in your derived shaders with `#ifdef` to customize their behavior for the depth or distance * scenarios, e.g. skipping antialiasing or expensive shader logic. */ function createDerivedMaterial(baseMaterial, options) { const optionsKey = getKeyForOptions(options); let ctorsByDerivation = CONSTRUCTOR_CACHE.get(baseMaterial); if (!ctorsByDerivation) CONSTRUCTOR_CACHE.set(baseMaterial, ctorsByDerivation = Object.create(null)); if (ctorsByDerivation[optionsKey]) return new ctorsByDerivation[optionsKey](); const privateBeforeCompileProp = `_onBeforeCompile${optionsKey}`; const onBeforeCompile = function(shaderInfo, renderer) { baseMaterial.onBeforeCompile.call(this, shaderInfo, renderer); const cacheKey = this.customProgramCacheKey() + "|" + shaderInfo.vertexShader + "|" + shaderInfo.fragmentShader; let upgradedShaders = SHADER_UPGRADE_CACHE[cacheKey]; if (!upgradedShaders) upgradedShaders = SHADER_UPGRADE_CACHE[cacheKey] = upgradeShaders(this, shaderInfo, options, optionsKey); shaderInfo.vertexShader = upgradedShaders.vertexShader; shaderInfo.fragmentShader = upgradedShaders.fragmentShader; assign$1(shaderInfo.uniforms, this.uniforms); if (options.timeUniform) shaderInfo.uniforms[options.timeUniform] = { get value() { return Date.now() - epoch; } }; if (this[privateBeforeCompileProp]) this[privateBeforeCompileProp](shaderInfo); }; const DerivedMaterial = function DerivedMaterial() { return derive(options.chained ? baseMaterial : baseMaterial.clone()); }; const derive = function(base) { const derived = Object.create(base, descriptor); Object.defineProperty(derived, "baseMaterial", { value: baseMaterial }); Object.defineProperty(derived, "id", { value: materialInstanceId++ }); derived.uuid = generateUUID(); derived.uniforms = assign$1({}, base.uniforms, options.uniforms); derived.defines = assign$1({}, base.defines, options.defines); derived.defines[`TROIKA_DERIVED_MATERIAL_${optionsKey}`] = ""; derived.extensions = assign$1({}, base.extensions, options.extensions); derived._listeners = void 0; return derived; }; const descriptor = { constructor: { value: DerivedMaterial }, isDerivedMaterial: { value: true }, type: { get: () => baseMaterial.type, set: (value) => { baseMaterial.type = value; } }, isDerivedFrom: { writable: true, configurable: true, value: function(testMaterial) { const base = this.baseMaterial; return testMaterial === base || base.isDerivedMaterial && base.isDerivedFrom(testMaterial) || false; } }, customProgramCacheKey: { writable: true, configurable: true, value: function() { return baseMaterial.customProgramCacheKey() + "|" + optionsKey; } }, onBeforeCompile: { get() { return onBeforeCompile; }, set(fn) { this[privateBeforeCompileProp] = fn; } }, copy: { writable: true, configurable: true, value: function(source) { baseMaterial.copy.call(this, source); if (!baseMaterial.isShaderMaterial && !baseMaterial.isDerivedMaterial) { assign$1(this.extensions, source.extensions); assign$1(this.defines, source.defines); assign$1(this.uniforms, UniformsUtils.clone(source.uniforms)); } return this; } }, clone: { writable: true, configurable: true, value: function() { return derive(new baseMaterial.constructor()).copy(this); } }, /** * Utility to get a MeshDepthMaterial that will honor this derived material's vertex * transformations and discarded fragments. */ getDepthMaterial: { writable: true, configurable: true, value: function() { let depthMaterial = this._depthMaterial; if (!depthMaterial) { depthMaterial = this._depthMaterial = createDerivedMaterial(baseMaterial.isDerivedMaterial ? baseMaterial.getDepthMaterial() : new MeshDepthMaterial({ depthPacking: RGBADepthPacking }), options); depthMaterial.defines.IS_DEPTH_MATERIAL = ""; depthMaterial.uniforms = this.uniforms; } return depthMaterial; } }, /** * Utility to get a MeshDistanceMaterial that will honor this derived material's vertex * transformations and discarded fragments. */ getDistanceMaterial: { writable: true, configurable: true, value: function() { let distanceMaterial = this._distanceMaterial; if (!distanceMaterial) { distanceMaterial = this._distanceMaterial = createDerivedMaterial(baseMaterial.isDerivedMaterial ? baseMaterial.getDistanceMaterial() : new MeshDistanceMaterial(), options); distanceMaterial.defines.IS_DISTANCE_MATERIAL = ""; distanceMaterial.uniforms = this.uniforms; } return distanceMaterial; } }, dispose: { writable: true, configurable: true, value() { const { _depthMaterial, _distanceMaterial } = this; if (_depthMaterial) _depthMaterial.dispose(); if (_distanceMaterial) _distanceMaterial.dispose(); baseMaterial.dispose.call(this); } } }; ctorsByDerivation[optionsKey] = DerivedMaterial; return new DerivedMaterial(); } function upgradeShaders(material, { vertexShader, fragmentShader }, options, key) { let { vertexDefs, vertexMainIntro, vertexMainOutro, vertexTransform, fragmentDefs, fragmentMainIntro, fragmentMainOutro, fragmentColorTransform, customRewriter, timeUniform } = options; vertexDefs = vertexDefs || ""; vertexMainIntro = vertexMainIntro || ""; vertexMainOutro = vertexMainOutro || ""; fragmentDefs = fragmentDefs || ""; fragmentMainIntro = fragmentMainIntro || ""; fragmentMainOutro = fragmentMainOutro || ""; if (vertexTransform || customRewriter) vertexShader = expandShaderIncludes(vertexShader); if (fragmentColorTransform || customRewriter) { fragmentShader = fragmentShader.replace(/^[ \t]*#include <((?:tonemapping|encodings|colorspace|fog|premultiplied_alpha|dithering)_fragment)>/gm, "\n//!BEGIN_POST_CHUNK $1\n$&\n//!END_POST_CHUNK\n"); fragmentShader = expandShaderIncludes(fragmentShader); } if (customRewriter) { let res = customRewriter({ vertexShader, fragmentShader }); vertexShader = res.vertexShader; fragmentShader = res.fragmentShader; } if (fragmentColorTransform) { let postChunks = []; fragmentShader = fragmentShader.replace(/^\/\/!BEGIN_POST_CHUNK[^]+?^\/\/!END_POST_CHUNK/gm, (match) => { postChunks.push(match); return ""; }); fragmentMainOutro = `${fragmentColorTransform}\n${postChunks.join("\n")}\n${fragmentMainOutro}`; } if (timeUniform) { const code = `\nuniform float ${timeUniform};\n`; vertexDefs = code + vertexDefs; fragmentDefs = code + fragmentDefs; } if (vertexTransform) { vertexShader = `vec3 troika_position_${key}; vec3 troika_normal_${key}; vec2 troika_uv_${key}; ${vertexShader} `; vertexDefs = `${vertexDefs} void troikaVertexTransform${key}(inout vec3 position, inout vec3 normal, inout vec2 uv) { ${vertexTransform} } `; vertexMainIntro = ` troika_position_${key} = vec3(position); troika_normal_${key} = vec3(normal); troika_uv_${key} = vec2(uv); troikaVertexTransform${key}(troika_position_${key}, troika_normal_${key}, troika_uv_${key}); ${vertexMainIntro} `; vertexShader = vertexShader.replace(/\b(position|normal|uv)\b/g, (match, match1, index, fullStr) => { return /\battribute\s+vec[23]\s+$/.test(fullStr.substr(0, index)) ? match1 : `troika_${match1}_${key}`; }); if (!(material.map && material.map.channel > 0)) vertexShader = vertexShader.replace(/\bMAP_UV\b/g, `troika_uv_${key}`); } vertexShader = injectIntoShaderCode(vertexShader, key, vertexDefs, vertexMainIntro, vertexMainOutro); fragmentShader = injectIntoShaderCode(fragmentShader, key, fragmentDefs, fragmentMainIntro, fragmentMainOutro); return { vertexShader, fragmentShader }; } function injectIntoShaderCode(shaderCode, id, defs, intro, outro) { if (intro || outro || defs) { shaderCode = shaderCode.replace(voidMainRegExp, ` ${defs} void troikaOrigMain${id}() {`); shaderCode += ` void main() { ${intro} troikaOrigMain${id}(); ${outro} }`; } return shaderCode; } function optionsJsonReplacer(key, value) { return key === "uniforms" ? void 0 : typeof value === "function" ? value.toString() : value; } var _idCtr = 0; var optionsHashesToIds = /* @__PURE__ */ new Map(); function getKeyForOptions(options) { const optionsHash = JSON.stringify(options, optionsJsonReplacer); let id = optionsHashesToIds.get(optionsHash); if (id == null) optionsHashesToIds.set(optionsHash, id = ++_idCtr); return id; } //#endregion //#region node_modules/troika-three-text/dist/troika-three-text.esm.js /*! Custom build of Typr.ts (https://github.com/fredli74/Typr.ts) for use in Troika text rendering. Original MIT license applies: https://github.com/fredli74/Typr.ts/blob/master/LICENSE */ function typrFactory() { return "undefined" == typeof window && (self.window = self), function(r) { var e = { parse: function(r) { var t = e._bin, a = new Uint8Array(r); if ("ttcf" == t.readASCII(a, 0, 4)) { var n = 4; t.readUshort(a, n), n += 2, t.readUshort(a, n), n += 2; var o = t.readUint(a, n); n += 4; for (var s = [], i = 0; i < o; i++) { var h = t.readUint(a, n); n += 4, s.push(e._readFont(a, h)); } return s; } return [e._readFont(a, 0)]; }, _readFont: function(r, t) { var a = e._bin, n = t; a.readFixed(r, t), t += 4; var o = a.readUshort(r, t); t += 2, a.readUshort(r, t), t += 2, a.readUshort(r, t), t += 2, a.readUshort(r, t), t += 2; for (var s = [ "cmap", "head", "hhea", "maxp", "hmtx", "name", "OS/2", "post", "loca", "glyf", "kern", "CFF ", "GDEF", "GPOS", "GSUB", "SVG " ], i = { _data: r, _offset: n }, h = {}, d = 0; d < o; d++) { var f = a.readASCII(r, t, 4); t += 4, a.readUint(r, t), t += 4; var u = a.readUint(r, t); t += 4; var l = a.readUint(r, t); t += 4, h[f] = { offset: u, length: l }; } for (d = 0; d < s.length; d++) { var v = s[d]; h[v] && (i[v.trim()] = e[v.trim()].parse(r, h[v].offset, h[v].length, i)); } return i; }, _tabOffset: function(r, t, a) { for (var n = e._bin, o = n.readUshort(r, a + 4), s = a + 12, i = 0; i < o; i++) { var h = n.readASCII(r, s, 4); s += 4, n.readUint(r, s), s += 4; var d = n.readUint(r, s); if (s += 4, n.readUint(r, s), s += 4, h == t) return d; } return 0; } }; e._bin = { readFixed: function(r, e) { return (r[e] << 8 | r[e + 1]) + (r[e + 2] << 8 | r[e + 3]) / 65540; }, readF2dot14: function(r, t) { return e._bin.readShort(r, t) / 16384; }, readInt: function(r, t) { return e._bin._view(r).getInt32(t); }, readInt8: function(r, t) { return e._bin._view(r).getInt8(t); }, readShort: function(r, t) { return e._bin._view(r).getInt16(t); }, readUshort: function(r, t) { return e._bin._view(r).getUint16(t); }, readUshorts: function(r, t, a) { for (var n = [], o = 0; o < a; o++) n.push(e._bin.readUshort(r, t + 2 * o)); return n; }, readUint: function(r, t) { return e._bin._view(r).getUint32(t); }, readUint64: function(r, t) { return 4294967296 * e._bin.readUint(r, t) + e._bin.readUint(r, t + 4); }, readASCII: function(r, e, t) { for (var a = "", n = 0; n < t; n++) a += String.fromCharCode(r[e + n]); return a; }, readUnicode: function(r, e, t) { for (var a = "", n = 0; n < t; n++) { var o = r[e++] << 8 | r[e++]; a += String.fromCharCode(o); } return a; }, _tdec: "undefined" != typeof window && window.TextDecoder ? new window.TextDecoder() : null, readUTF8: function(r, t, a) { var n = e._bin._tdec; return n && 0 == t && a == r.length ? n.decode(r) : e._bin.readASCII(r, t, a); }, readBytes: function(r, e, t) { for (var a = [], n = 0; n < t; n++) a.push(r[e + n]); return a; }, readASCIIArray: function(r, e, t) { for (var a = [], n = 0; n < t; n++) a.push(String.fromCharCode(r[e + n])); return a; }, _view: function(r) { return r._dataView || (r._dataView = r.buffer ? new DataView(r.buffer, r.byteOffset, r.byteLength) : new DataView(new Uint8Array(r).buffer)); } }, e._lctf = {}, e._lctf.parse = function(r, t, a, n, o) { var s = e._bin, i = {}, h = t; s.readFixed(r, t), t += 4; var d = s.readUshort(r, t); t += 2; var f = s.readUshort(r, t); t += 2; var u = s.readUshort(r, t); return t += 2, i.scriptList = e._lctf.readScriptList(r, h + d), i.featureList = e._lctf.readFeatureList(r, h + f), i.lookupList = e._lctf.readLookupList(r, h + u, o), i; }, e._lctf.readLookupList = function(r, t, a) { var n = e._bin, o = t, s = [], i = n.readUshort(r, t); t += 2; for (var h = 0; h < i; h++) { var d = n.readUshort(r, t); t += 2; var f = e._lctf.readLookupTable(r, o + d, a); s.push(f); } return s; }, e._lctf.readLookupTable = function(r, t, a) { var n = e._bin, o = t, s = { tabs: [] }; s.ltype = n.readUshort(r, t), t += 2, s.flag = n.readUshort(r, t), t += 2; var i = n.readUshort(r, t); t += 2; for (var h = s.ltype, d = 0; d < i; d++) { var f = n.readUshort(r, t); t += 2; var u = a(r, h, o + f, s); s.tabs.push(u); } return s; }, e._lctf.numOfOnes = function(r) { for (var e = 0, t = 0; t < 32; t++) 0 != (r >>> t & 1) && e++; return e; }, e._lctf.readClassDef = function(r, t) { var a = e._bin, n = [], o = a.readUshort(r, t); if (t += 2, 1 == o) { var s = a.readUshort(r, t); t += 2; var i = a.readUshort(r, t); t += 2; for (var h = 0; h < i; h++) n.push(s + h), n.push(s + h), n.push(a.readUshort(r, t)), t += 2; } if (2 == o) { var d = a.readUshort(r, t); t += 2; for (h = 0; h < d; h++) n.push(a.readUshort(r, t)), t += 2, n.push(a.readUshort(r, t)), t += 2, n.push(a.readUshort(r, t)), t += 2; } return n; }, e._lctf.getInterval = function(r, e) { for (var t = 0; t < r.length; t += 3) { var a = r[t], n = r[t + 1]; if (r[t + 2], a <= e && e <= n) return t; } return -1; }, e._lctf.readCoverage = function(r, t) { var a = e._bin, n = {}; n.fmt = a.readUshort(r, t), t += 2; var o = a.readUshort(r, t); return t += 2, 1 == n.fmt && (n.tab = a.readUshorts(r, t, o)), 2 == n.fmt && (n.tab = a.readUshorts(r, t, 3 * o)), n; }, e._lctf.coverageIndex = function(r, t) { var a = r.tab; if (1 == r.fmt) return a.indexOf(t); if (2 == r.fmt) { var n = e._lctf.getInterval(a, t); if (-1 != n) return a[n + 2] + (t - a[n]); } return -1; }, e._lctf.readFeatureList = function(r, t) { var a = e._bin, n = t, o = [], s = a.readUshort(r, t); t += 2; for (var i = 0; i < s; i++) { var h = a.readASCII(r, t, 4); t += 4; var d = a.readUshort(r, t); t += 2; var f = e._lctf.readFeatureTable(r, n + d); f.tag = h.trim(), o.push(f); } return o; }, e._lctf.readFeatureTable = function(r, t) { var a = e._bin, n = t, o = {}, s = a.readUshort(r, t); t += 2, s > 0 && (o.featureParams = n + s); var i = a.readUshort(r, t); t += 2, o.tab = []; for (var h = 0; h < i; h++) o.tab.push(a.readUshort(r, t + 2 * h)); return o; }, e._lctf.readScriptList = function(r, t) { var a = e._bin, n = t, o = {}, s = a.readUshort(r, t); t += 2; for (var i = 0; i < s; i++) { var h = a.readASCII(r, t, 4); t += 4; var d = a.readUshort(r, t); t += 2, o[h.trim()] = e._lctf.readScriptTable(r, n + d); } return o; }, e._lctf.readScriptTable = function(r, t) { var a = e._bin, n = t, o = {}, s = a.readUshort(r, t); t += 2, s > 0 && (o.default = e._lctf.readLangSysTable(r, n + s)); var i = a.readUshort(r, t); t += 2; for (var h = 0; h < i; h++) { var d = a.readASCII(r, t, 4); t += 4; var f = a.readUshort(r, t); t += 2, o[d.trim()] = e._lctf.readLangSysTable(r, n + f); } return o; }, e._lctf.readLangSysTable = function(r, t) { var a = e._bin, n = {}; a.readUshort(r, t), t += 2, n.reqFeature = a.readUshort(r, t), t += 2; var o = a.readUshort(r, t); return t += 2, n.features = a.readUshorts(r, t, o), n; }, e.CFF = {}, e.CFF.parse = function(r, t, a) { var n = e._bin; (r = new Uint8Array(r.buffer, t, a))[t = 0], r[++t], r[++t], r[++t], t++; var o = []; t = e.CFF.readIndex(r, t, o); for (var s = [], i = 0; i < o.length - 1; i++) s.push(n.readASCII(r, t + o[i], o[i + 1] - o[i])); t += o[o.length - 1]; var h = []; t = e.CFF.readIndex(r, t, h); var d = []; for (i = 0; i < h.length - 1; i++) d.push(e.CFF.readDict(r, t + h[i], t + h[i + 1])); t += h[h.length - 1]; var f = d[0], u = []; t = e.CFF.readIndex(r, t, u); var l = []; for (i = 0; i < u.length - 1; i++) l.push(n.readASCII(r, t + u[i], u[i + 1] - u[i])); if (t += u[u.length - 1], e.CFF.readSubrs(r, t, f), f.CharStrings) { t = f.CharStrings; u = []; t = e.CFF.readIndex(r, t, u); var v = []; for (i = 0; i < u.length - 1; i++) v.push(n.readBytes(r, t + u[i], u[i + 1] - u[i])); f.CharStrings = v; } if (f.ROS) { t = f.FDArray; var c = []; t = e.CFF.readIndex(r, t, c), f.FDArray = []; for (i = 0; i < c.length - 1; i++) { var p = e.CFF.readDict(r, t + c[i], t + c[i + 1]); e.CFF._readFDict(r, p, l), f.FDArray.push(p); } t += c[c.length - 1], t = f.FDSelect, f.FDSelect = []; var U = r[t]; if (t++, 3 != U) throw U; var g = n.readUshort(r, t); t += 2; for (i = 0; i < g + 1; i++) f.FDSelect.push(n.readUshort(r, t), r[t + 2]), t += 3; } return f.Encoding && (f.Encoding = e.CFF.readEncoding(r, f.Encoding, f.CharStrings.length)), f.charset && (f.charset = e.CFF.readCharset(r, f.charset, f.CharStrings.length)), e.CFF._readFDict(r, f, l), f; }, e.CFF._readFDict = function(r, t, a) { var n; for (var o in t.Private && (n = t.Private[1], t.Private = e.CFF.readDict(r, n, n + t.Private[0]), t.Private.Subrs && e.CFF.readSubrs(r, n + t.Private.Subrs, t.Private)), t) -1 != [ "FamilyName", "FontName", "FullName", "Notice", "version", "Copyright" ].indexOf(o) && (t[o] = a[t[o] - 426 + 35]); }, e.CFF.readSubrs = function(r, t, a) { var n = e._bin, o = []; t = e.CFF.readIndex(r, t, o); var s, i = o.length; s = i < 1240 ? 107 : i < 33900 ? 1131 : 32768, a.Bias = s, a.Subrs = []; for (var h = 0; h < o.length - 1; h++) a.Subrs.push(n.readBytes(r, t + o[h], o[h + 1] - o[h])); }, e.CFF.tableSE = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0 ], e.CFF.glyphByUnicode = function(r, e) { for (var t = 0; t < r.charset.length; t++) if (r.charset[t] == e) return t; return -1; }, e.CFF.glyphBySE = function(r, t) { return t < 0 || t > 255 ? -1 : e.CFF.glyphByUnicode(r, e.CFF.tableSE[t]); }, e.CFF.readEncoding = function(r, t, a) { e._bin; var n = [".notdef"], o = r[t]; if (t++, 0 != o) throw "error: unknown encoding format: " + o; var s = r[t]; t++; for (var i = 0; i < s; i++) n.push(r[t + i]); return n; }, e.CFF.readCharset = function(r, t, a) { var n = e._bin, o = [".notdef"], s = r[t]; if (t++, 0 == s) for (var i = 0; i < a; i++) { var h = n.readUshort(r, t); t += 2, o.push(h); } else { if (1 != s && 2 != s) throw "error: format: " + s; for (; o.length < a;) { h = n.readUshort(r, t); t += 2; var d = 0; 1 == s ? (d = r[t], t++) : (d = n.readUshort(r, t), t += 2); for (i = 0; i <= d; i++) o.push(h), h++; } } return o; }, e.CFF.readIndex = function(r, t, a) { var n = e._bin, o = n.readUshort(r, t) + 1, s = r[t += 2]; if (t++, 1 == s) for (var i = 0; i < o; i++) a.push(r[t + i]); else if (2 == s) for (i = 0; i < o; i++) a.push(n.readUshort(r, t + 2 * i)); else if (3 == s) for (i = 0; i < o; i++) a.push(16777215 & n.readUint(r, t + 3 * i - 1)); else if (1 != o) throw "unsupported offset size: " + s + ", count: " + o; return (t += o * s) - 1; }, e.CFF.getCharString = function(r, t, a) { var n = e._bin, o = r[t], s = r[t + 1]; r[t + 2], r[t + 3], r[t + 4]; var i = 1, h = null, d = null; o <= 20 && (h = o, i = 1), 12 == o && (h = 100 * o + s, i = 2), 21 <= o && o <= 27 && (h = o, i = 1), 28 == o && (d = n.readShort(r, t + 1), i = 3), 29 <= o && o <= 31 && (h = o, i = 1), 32 <= o && o <= 246 && (d = o - 139, i = 1), 247 <= o && o <= 250 && (d = 256 * (o - 247) + s + 108, i = 2), 251 <= o && o <= 254 && (d = 256 * -(o - 251) - s - 108, i = 2), 255 == o && (d = n.readInt(r, t + 1) / 65535, i = 5), a.val = null != d ? d : "o" + h, a.size = i; }, e.CFF.readCharString = function(r, t, a) { for (var n = t + a, o = e._bin, s = []; t < n;) { var i = r[t], h = r[t + 1]; r[t + 2], r[t + 3], r[t + 4]; var d = 1, f = null, u = null; i <= 20 && (f = i, d = 1), 12 == i && (f = 100 * i + h, d = 2), 19 != i && 20 != i || (f = i, d = 2), 21 <= i && i <= 27 && (f = i, d = 1), 28 == i && (u = o.readShort(r, t + 1), d = 3), 29 <= i && i <= 31 && (f = i, d = 1), 32 <= i && i <= 246 && (u = i - 139, d = 1), 247 <= i && i <= 250 && (u = 256 * (i - 247) + h + 108, d = 2), 251 <= i && i <= 254 && (u = 256 * -(i - 251) - h - 108, d = 2), 255 == i && (u = o.readInt(r, t + 1) / 65535, d = 5), s.push(null != u ? u : "o" + f), t += d; } return s; }, e.CFF.readDict = function(r, t, a) { for (var n = e._bin, o = {}, s = []; t < a;) { var i = r[t], h = r[t + 1]; r[t + 2], r[t + 3], r[t + 4]; var d = 1, f = null, u = null; if (28 == i && (u = n.readShort(r, t + 1), d = 3), 29 == i && (u = n.readInt(r, t + 1), d = 5), 32 <= i && i <= 246 && (u = i - 139, d = 1), 247 <= i && i <= 250 && (u = 256 * (i - 247) + h + 108, d = 2), 251 <= i && i <= 254 && (u = 256 * -(i - 251) - h - 108, d = 2), 255 == i) throw u = n.readInt(r, t + 1) / 65535, d = 5, "unknown number"; if (30 == i) { var l = []; for (d = 1;;) { var v = r[t + d]; d++; var c = v >> 4, p = 15 & v; if (15 != c && l.push(c), 15 != p && l.push(p), 15 == p) break; } for (var U = "", g = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ".", "e", "e-", "reserved", "-", "endOfNumber" ], S = 0; S < l.length; S++) U += g[l[S]]; u = parseFloat(U); } if (i <= 21) { if (f = [ "version", "Notice", "FullName", "FamilyName", "Weight", "FontBBox", "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "escape", "UniqueID", "XUID", "charset", "Encoding", "CharStrings", "Private", "Subrs", "defaultWidthX", "nominalWidthX" ][i], d = 1, 12 == i) f = [ "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", "StemSnapH", "StemSnapV", "ForceBold", 0, 0, "LanguageGroup", "ExpansionFactor", "initialRandomSeed", "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", 0, 0, 0, 0, 0, 0, "ROS", "CIDFontVersion", "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", "FDArray", "FDSelect", "FontName" ][h], d = 2; } null != f ? (o[f] = 1 == s.length ? s[0] : s, s = []) : s.push(u), t += d; } return o; }, e.cmap = {}, e.cmap.parse = function(r, t, a) { r = new Uint8Array(r.buffer, t, a), t = 0; var n = e._bin, o = {}; n.readUshort(r, t), t += 2; var s = n.readUshort(r, t); t += 2; var i = []; o.tables = []; for (var h = 0; h < s; h++) { var d = n.readUshort(r, t); t += 2; var f = n.readUshort(r, t); t += 2; var u = n.readUint(r, t); t += 4; var l = "p" + d + "e" + f, v = i.indexOf(u); if (-1 == v) { var c; v = o.tables.length, i.push(u); var p = n.readUshort(r, u); 0 == p ? c = e.cmap.parse0(r, u) : 4 == p ? c = e.cmap.parse4(r, u) : 6 == p ? c = e.cmap.parse6(r, u) : 12 == p ? c = e.cmap.parse12(r, u) : console.debug("unknown format: " + p, d, f, u), o.tables.push(c); } if (null != o[l]) throw "multiple tables for one platform+encoding"; o[l] = v; } return o; }, e.cmap.parse0 = function(r, t) { var a = e._bin, n = {}; n.format = a.readUshort(r, t), t += 2; var o = a.readUshort(r, t); t += 2, a.readUshort(r, t), t += 2, n.map = []; for (var s = 0; s < o - 6; s++) n.map.push(r[t + s]); return n; }, e.cmap.parse4 = function(r, t) { var a = e._bin, n = t, o = {}; o.format = a.readUshort(r, t), t += 2; var s = a.readUshort(r, t); t += 2, a.readUshort(r, t), t += 2; var i = a.readUshort(r, t); t += 2; var h = i / 2; o.searchRange = a.readUshort(r, t), t += 2, o.entrySelector = a.readUshort(r, t), t += 2, o.rangeShift = a.readUshort(r, t), t += 2, o.endCount = a.readUshorts(r, t, h), t += 2 * h, t += 2, o.startCount = a.readUshorts(r, t, h), t += 2 * h, o.idDelta = []; for (var d = 0; d < h; d++) o.idDelta.push(a.readShort(r, t)), t += 2; for (o.idRangeOffset = a.readUshorts(r, t, h), t += 2 * h, o.glyphIdArray = []; t < n + s;) o.glyphIdArray.push(a.readUshort(r, t)), t += 2; return o; }, e.cmap.parse6 = function(r, t) { var a = e._bin, n = {}; n.format = a.readUshort(r, t), t += 2, a.readUshort(r, t), t += 2, a.readUshort(r, t), t += 2, n.firstCode = a.readUshort(r, t), t += 2; var o = a.readUshort(r, t); t += 2, n.glyphIdArray = []; for (var s = 0; s < o; s++) n.glyphIdArray.push(a.readUshort(r, t)), t += 2; return n; }, e.cmap.parse12 = function(r, t) { var a = e._bin, n = {}; n.format = a.readUshort(r, t), t += 2, t += 2, a.readUint(r, t), t += 4, a.readUint(r, t), t += 4; var o = a.readUint(r, t); t += 4, n.groups = []; for (var s = 0; s < o; s++) { var i = t + 12 * s, h = a.readUint(r, i + 0), d = a.readUint(r, i + 4), f = a.readUint(r, i + 8); n.groups.push([ h, d, f ]); } return n; }, e.glyf = {}, e.glyf.parse = function(r, e, t, a) { for (var n = [], o = 0; o < a.maxp.numGlyphs; o++) n.push(null); return n; }, e.glyf._parseGlyf = function(r, t) { var a = e._bin, n = r._data, o = e._tabOffset(n, "glyf", r._offset) + r.loca[t]; if (r.loca[t] == r.loca[t + 1]) return null; var s = {}; if (s.noc = a.readShort(n, o), o += 2, s.xMin = a.readShort(n, o), o += 2, s.yMin = a.readShort(n, o), o += 2, s.xMax = a.readShort(n, o), o += 2, s.yMax = a.readShort(n, o), o += 2, s.xMin >= s.xMax || s.yMin >= s.yMax) return null; if (s.noc > 0) { s.endPts = []; for (var i = 0; i < s.noc; i++) s.endPts.push(a.readUshort(n, o)), o += 2; var h = a.readUshort(n, o); if (o += 2, n.length - o < h) return null; s.instructions = a.readBytes(n, o, h), o += h; var d = s.endPts[s.noc - 1] + 1; s.flags = []; for (i = 0; i < d; i++) { var f = n[o]; if (o++, s.flags.push(f), 0 != (8 & f)) { var u = n[o]; o++; for (var l = 0; l < u; l++) s.flags.push(f), i++; } } s.xs = []; for (i = 0; i < d; i++) { var v = 0 != (2 & s.flags[i]), c = 0 != (16 & s.flags[i]); v ? (s.xs.push(c ? n[o] : -n[o]), o++) : c ? s.xs.push(0) : (s.xs.push(a.readShort(n, o)), o += 2); } s.ys = []; for (i = 0; i < d; i++) { v = 0 != (4 & s.flags[i]), c = 0 != (32 & s.flags[i]); v ? (s.ys.push(c ? n[o] : -n[o]), o++) : c ? s.ys.push(0) : (s.ys.push(a.readShort(n, o)), o += 2); } var p = 0, U = 0; for (i = 0; i < d; i++) p += s.xs[i], U += s.ys[i], s.xs[i] = p, s.ys[i] = U; } else { var g; s.parts = []; do { g = a.readUshort(n, o), o += 2; var S = { m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 }, p1: -1, p2: -1 }; if (s.parts.push(S), S.glyphIndex = a.readUshort(n, o), o += 2, 1 & g) { var m = a.readShort(n, o); o += 2; var b = a.readShort(n, o); o += 2; } else { m = a.readInt8(n, o); o++; b = a.readInt8(n, o); o++; } 2 & g ? (S.m.tx = m, S.m.ty = b) : (S.p1 = m, S.p2 = b), 8 & g ? (S.m.a = S.m.d = a.readF2dot14(n, o), o += 2) : 64 & g ? (S.m.a = a.readF2dot14(n, o), o += 2, S.m.d = a.readF2dot14(n, o), o += 2) : 128 & g && (S.m.a = a.readF2dot14(n, o), o += 2, S.m.b = a.readF2dot14(n, o), o += 2, S.m.c = a.readF2dot14(n, o), o += 2, S.m.d = a.readF2dot14(n, o), o += 2); } while (32 & g); if (256 & g) { var y = a.readUshort(n, o); o += 2, s.instr = []; for (i = 0; i < y; i++) s.instr.push(n[o]), o++; } } return s; }, e.GDEF = {}, e.GDEF.parse = function(r, t, a, n) { var o = t; t += 4; var s = e._bin.readUshort(r, t); return { glyphClassDef: 0 === s ? null : e._lctf.readClassDef(r, o + s) }; }, e.GPOS = {}, e.GPOS.parse = function(r, t, a, n) { return e._lctf.parse(r, t, a, n, e.GPOS.subt); }, e.GPOS.subt = function(r, t, a, n) { var o = e._bin, s = a, i = {}; if (i.fmt = o.readUshort(r, a), a += 2, 1 == t || 2 == t || 3 == t || 7 == t || 8 == t && i.fmt <= 2) { var h = o.readUshort(r, a); a += 2, i.coverage = e._lctf.readCoverage(r, h + s); } if (1 == t && 1 == i.fmt) { var d = o.readUshort(r, a); a += 2, 0 != d && (i.pos = e.GPOS.readValueRecord(r, a, d)); } else if (2 == t && i.fmt >= 1 && i.fmt <= 2) { d = o.readUshort(r, a); a += 2; var f = o.readUshort(r, a); a += 2; var u = e._lctf.numOfOnes(d), l = e._lctf.numOfOnes(f); if (1 == i.fmt) { i.pairsets = []; var v = o.readUshort(r, a); a += 2; for (var c = 0; c < v; c++) { var p = s + o.readUshort(r, a); a += 2; var U = o.readUshort(r, p); p += 2; for (var g = [], S = 0; S < U; S++) { var m = o.readUshort(r, p); p += 2, 0 != d && (P = e.GPOS.readValueRecord(r, p, d), p += 2 * u), 0 != f && (x = e.GPOS.readValueRecord(r, p, f), p += 2 * l), g.push({ gid2: m, val1: P, val2: x }); } i.pairsets.push(g); } } if (2 == i.fmt) { var b = o.readUshort(r, a); a += 2; var y = o.readUshort(r, a); a += 2; var F = o.readUshort(r, a); a += 2; var C = o.readUshort(r, a); a += 2, i.classDef1 = e._lctf.readClassDef(r, s + b), i.classDef2 = e._lctf.readClassDef(r, s + y), i.matrix = []; for (c = 0; c < F; c++) { var _ = []; for (S = 0; S < C; S++) { var P = null, x = null; 0 != d && (P = e.GPOS.readValueRecord(r, a, d), a += 2 * u), 0 != f && (x = e.GPOS.readValueRecord(r, a, f), a += 2 * l), _.push({ val1: P, val2: x }); } i.matrix.push(_); } } } else if (4 == t && 1 == i.fmt) i.markCoverage = e._lctf.readCoverage(r, o.readUshort(r, a) + s), i.baseCoverage = e._lctf.readCoverage(r, o.readUshort(r, a + 2) + s), i.markClassCount = o.readUshort(r, a + 4), i.markArray = e.GPOS.readMarkArray(r, o.readUshort(r, a + 6) + s), i.baseArray = e.GPOS.readBaseArray(r, o.readUshort(r, a + 8) + s, i.markClassCount); else if (6 == t && 1 == i.fmt) i.mark1Coverage = e._lctf.readCoverage(r, o.readUshort(r, a) + s), i.mark2Coverage = e._lctf.readCoverage(r, o.readUshort(r, a + 2) + s), i.markClassCount = o.readUshort(r, a + 4), i.mark1Array = e.GPOS.readMarkArray(r, o.readUshort(r, a + 6) + s), i.mark2Array = e.GPOS.readBaseArray(r, o.readUshort(r, a + 8) + s, i.markClassCount); else { if (9 == t && 1 == i.fmt) { var I = o.readUshort(r, a); a += 2; var w = o.readUint(r, a); if (a += 4, 9 == n.ltype) n.ltype = I; else if (n.ltype != I) throw "invalid extension substitution"; return e.GPOS.subt(r, n.ltype, s + w); } console.debug("unsupported GPOS table LookupType", t, "format", i.fmt); } return i; }, e.GPOS.readValueRecord = function(r, t, a) { var n = e._bin, o = []; return o.push(1 & a ? n.readShort(r, t) : 0), t += 1 & a ? 2 : 0, o.push(2 & a ? n.readShort(r, t) : 0), t += 2 & a ? 2 : 0, o.push(4 & a ? n.readShort(r, t) : 0), t += 4 & a ? 2 : 0, o.push(8 & a ? n.readShort(r, t) : 0), t += 8 & a ? 2 : 0, o; }, e.GPOS.readBaseArray = function(r, t, a) { var n = e._bin, o = [], s = t, i = n.readUshort(r, t); t += 2; for (var h = 0; h < i; h++) { for (var d = [], f = 0; f < a; f++) d.push(e.GPOS.readAnchorRecord(r, s + n.readUshort(r, t))), t += 2; o.push(d); } return o; }, e.GPOS.readMarkArray = function(r, t) { var a = e._bin, n = [], o = t, s = a.readUshort(r, t); t += 2; for (var i = 0; i < s; i++) { var h = e.GPOS.readAnchorRecord(r, a.readUshort(r, t + 2) + o); h.markClass = a.readUshort(r, t), n.push(h), t += 4; } return n; }, e.GPOS.readAnchorRecord = function(r, t) { var a = e._bin, n = {}; return n.fmt = a.readUshort(r, t), n.x = a.readShort(r, t + 2), n.y = a.readShort(r, t + 4), n; }, e.GSUB = {}, e.GSUB.parse = function(r, t, a, n) { return e._lctf.parse(r, t, a, n, e.GSUB.subt); }, e.GSUB.subt = function(r, t, a, n) { var o = e._bin, s = a, i = {}; if (i.fmt = o.readUshort(r, a), a += 2, 1 != t && 2 != t && 4 != t && 5 != t && 6 != t) return null; if (1 == t || 2 == t || 4 == t || 5 == t && i.fmt <= 2 || 6 == t && i.fmt <= 2) { var h = o.readUshort(r, a); a += 2, i.coverage = e._lctf.readCoverage(r, s + h); } if (1 == t && i.fmt >= 1 && i.fmt <= 2) { if (1 == i.fmt) i.delta = o.readShort(r, a), a += 2; else if (2 == i.fmt) { var d = o.readUshort(r, a); a += 2, i.newg = o.readUshorts(r, a, d), a += 2 * i.newg.length; } } else if (2 == t && 1 == i.fmt) { d = o.readUshort(r, a); a += 2, i.seqs = []; for (var f = 0; f < d; f++) { var u = o.readUshort(r, a) + s; a += 2; var l = o.readUshort(r, u); i.seqs.push(o.readUshorts(r, u + 2, l)); } } else if (4 == t) { i.vals = []; d = o.readUshort(r, a); a += 2; for (f = 0; f < d; f++) { var v = o.readUshort(r, a); a += 2, i.vals.push(e.GSUB.readLigatureSet(r, s + v)); } } else if (5 == t && 2 == i.fmt) { if (2 == i.fmt) { var c = o.readUshort(r, a); a += 2, i.cDef = e._lctf.readClassDef(r, s + c), i.scset = []; var p = o.readUshort(r, a); a += 2; for (f = 0; f < p; f++) { var U = o.readUshort(r, a); a += 2, i.scset.push(0 == U ? null : e.GSUB.readSubClassSet(r, s + U)); } } } else if (6 == t && 3 == i.fmt) { if (3 == i.fmt) { for (f = 0; f < 3; f++) { d = o.readUshort(r, a); a += 2; for (var g = [], S = 0; S < d; S++) g.push(e._lctf.readCoverage(r, s + o.readUshort(r, a + 2 * S))); a += 2 * d, 0 == f && (i.backCvg = g), 1 == f && (i.inptCvg = g), 2 == f && (i.ahedCvg = g); } d = o.readUshort(r, a); a += 2, i.lookupRec = e.GSUB.readSubstLookupRecords(r, a, d); } } else { if (7 == t && 1 == i.fmt) { var m = o.readUshort(r, a); a += 2; var b = o.readUint(r, a); if (a += 4, 9 == n.ltype) n.ltype = m; else if (n.ltype != m) throw "invalid extension substitution"; return e.GSUB.subt(r, n.ltype, s + b); } console.debug("unsupported GSUB table LookupType", t, "format", i.fmt); } return i; }, e.GSUB.readSubClassSet = function(r, t) { var a = e._bin.readUshort, n = t, o = [], s = a(r, t); t += 2; for (var i = 0; i < s; i++) { var h = a(r, t); t += 2, o.push(e.GSUB.readSubClassRule(r, n + h)); } return o; }, e.GSUB.readSubClassRule = function(r, t) { var a = e._bin.readUshort, n = {}, o = a(r, t), s = a(r, t += 2); t += 2, n.input = []; for (var i = 0; i < o - 1; i++) n.input.push(a(r, t)), t += 2; return n.substLookupRecords = e.GSUB.readSubstLookupRecords(r, t, s), n; }, e.GSUB.readSubstLookupRecords = function(r, t, a) { for (var n = e._bin.readUshort, o = [], s = 0; s < a; s++) o.push(n(r, t), n(r, t + 2)), t += 4; return o; }, e.GSUB.readChainSubClassSet = function(r, t) { var a = e._bin, n = t, o = [], s = a.readUshort(r, t); t += 2; for (var i = 0; i < s; i++) { var h = a.readUshort(r, t); t += 2, o.push(e.GSUB.readChainSubClassRule(r, n + h)); } return o; }, e.GSUB.readChainSubClassRule = function(r, t) { for (var a = e._bin, n = {}, o = [ "backtrack", "input", "lookahead" ], s = 0; s < o.length; s++) { var i = a.readUshort(r, t); t += 2, 1 == s && i--, n[o[s]] = a.readUshorts(r, t, i), t += 2 * n[o[s]].length; } i = a.readUshort(r, t); return t += 2, n.subst = a.readUshorts(r, t, 2 * i), t += 2 * n.subst.length, n; }, e.GSUB.readLigatureSet = function(r, t) { var a = e._bin, n = t, o = [], s = a.readUshort(r, t); t += 2; for (var i = 0; i < s; i++) { var h = a.readUshort(r, t); t += 2, o.push(e.GSUB.readLigature(r, n + h)); } return o; }, e.GSUB.readLigature = function(r, t) { var a = e._bin, n = { chain: [] }; n.nglyph = a.readUshort(r, t), t += 2; var o = a.readUshort(r, t); t += 2; for (var s = 0; s < o - 1; s++) n.chain.push(a.readUshort(r, t)), t += 2; return n; }, e.head = {}, e.head.parse = function(r, t, a) { var n = e._bin, o = {}; return n.readFixed(r, t), t += 4, o.fontRevision = n.readFixed(r, t), t += 4, n.readUint(r, t), t += 4, n.readUint(r, t), t += 4, o.flags = n.readUshort(r, t), t += 2, o.unitsPerEm = n.readUshort(r, t), t += 2, o.created = n.readUint64(r, t), t += 8, o.modified = n.readUint64(r, t), t += 8, o.xMin = n.readShort(r, t), t += 2, o.yMin = n.readShort(r, t), t += 2, o.xMax = n.readShort(r, t), t += 2, o.yMax = n.readShort(r, t), t += 2, o.macStyle = n.readUshort(r, t), t += 2, o.lowestRecPPEM = n.readUshort(r, t), t += 2, o.fontDirectionHint = n.readShort(r, t), t += 2, o.indexToLocFormat = n.readShort(r, t), t += 2, o.glyphDataFormat = n.readShort(r, t), t += 2, o; }, e.hhea = {}, e.hhea.parse = function(r, t, a) { var n = e._bin, o = {}; return n.readFixed(r, t), t += 4, o.ascender = n.readShort(r, t), t += 2, o.descender = n.readShort(r, t), t += 2, o.lineGap = n.readShort(r, t), t += 2, o.advanceWidthMax = n.readUshort(r, t), t += 2, o.minLeftSideBearing = n.readShort(r, t), t += 2, o.minRightSideBearing = n.readShort(r, t), t += 2, o.xMaxExtent = n.readShort(r, t), t += 2, o.caretSlopeRise = n.readShort(r, t), t += 2, o.caretSlopeRun = n.readShort(r, t), t += 2, o.caretOffset = n.readShort(r, t), t += 2, t += 8, o.metricDataFormat = n.readShort(r, t), t += 2, o.numberOfHMetrics = n.readUshort(r, t), t += 2, o; }, e.hmtx = {}, e.hmtx.parse = function(r, t, a, n) { for (var o = e._bin, s = { aWidth: [], lsBearing: [] }, i = 0, h = 0, d = 0; d < n.maxp.numGlyphs; d++) d < n.hhea.numberOfHMetrics && (i = o.readUshort(r, t), t += 2, h = o.readShort(r, t), t += 2), s.aWidth.push(i), s.lsBearing.push(h); return s; }, e.kern = {}, e.kern.parse = function(r, t, a, n) { var o = e._bin, s = o.readUshort(r, t); if (t += 2, 1 == s) return e.kern.parseV1(r, t - 2, a, n); var i = o.readUshort(r, t); t += 2; for (var h = { glyph1: [], rval: [] }, d = 0; d < i; d++) { t += 2; a = o.readUshort(r, t); t += 2; var f = o.readUshort(r, t); t += 2; var u = f >>> 8; if (0 != (u &= 15)) throw "unknown kern table format: " + u; t = e.kern.readFormat0(r, t, h); } return h; }, e.kern.parseV1 = function(r, t, a, n) { var o = e._bin; o.readFixed(r, t), t += 4; var s = o.readUint(r, t); t += 4; for (var i = { glyph1: [], rval: [] }, h = 0; h < s; h++) { o.readUint(r, t), t += 4; var d = o.readUshort(r, t); t += 2, o.readUshort(r, t), t += 2; var f = d >>> 8; if (0 != (f &= 15)) throw "unknown kern table format: " + f; t = e.kern.readFormat0(r, t, i); } return i; }, e.kern.readFormat0 = function(r, t, a) { var n = e._bin, o = -1, s = n.readUshort(r, t); t += 2, n.readUshort(r, t), t += 2, n.readUshort(r, t), t += 2, n.readUshort(r, t), t += 2; for (var i = 0; i < s; i++) { var h = n.readUshort(r, t); t += 2; var d = n.readUshort(r, t); t += 2; var f = n.readShort(r, t); t += 2, h != o && (a.glyph1.push(h), a.rval.push({ glyph2: [], vals: [] })); var u = a.rval[a.rval.length - 1]; u.glyph2.push(d), u.vals.push(f), o = h; } return t; }, e.loca = {}, e.loca.parse = function(r, t, a, n) { var o = e._bin, s = [], i = n.head.indexToLocFormat, h = n.maxp.numGlyphs + 1; if (0 == i) for (var d = 0; d < h; d++) s.push(o.readUshort(r, t + (d << 1)) << 1); if (1 == i) for (d = 0; d < h; d++) s.push(o.readUint(r, t + (d << 2))); return s; }, e.maxp = {}, e.maxp.parse = function(r, t, a) { var n = e._bin, o = {}, s = n.readUint(r, t); return t += 4, o.numGlyphs = n.readUshort(r, t), t += 2, 65536 == s && (o.maxPoints = n.readUshort(r, t), t += 2, o.maxContours = n.readUshort(r, t), t += 2, o.maxCompositePoints = n.readUshort(r, t), t += 2, o.maxCompositeContours = n.readUshort(r, t), t += 2, o.maxZones = n.readUshort(r, t), t += 2, o.maxTwilightPoints = n.readUshort(r, t), t += 2, o.maxStorage = n.readUshort(r, t), t += 2, o.maxFunctionDefs = n.readUshort(r, t), t += 2, o.maxInstructionDefs = n.readUshort(r, t), t += 2, o.maxStackElements = n.readUshort(r, t), t += 2, o.maxSizeOfInstructions = n.readUshort(r, t), t += 2, o.maxComponentElements = n.readUshort(r, t), t += 2, o.maxComponentDepth = n.readUshort(r, t), t += 2), o; }, e.name = {}, e.name.parse = function(r, t, a) { var n = e._bin, o = {}; n.readUshort(r, t), t += 2; var s = n.readUshort(r, t); t += 2, n.readUshort(r, t); for (var i, h = [ "copyright", "fontFamily", "fontSubfamily", "ID", "fullName", "version", "postScriptName", "trademark", "manufacturer", "designer", "description", "urlVendor", "urlDesigner", "licence", "licenceURL", "---", "typoFamilyName", "typoSubfamilyName", "compatibleFull", "sampleText", "postScriptCID", "wwsFamilyName", "wwsSubfamilyName", "lightPalette", "darkPalette" ], d = t += 2, f = 0; f < s; f++) { var u = n.readUshort(r, t); t += 2; var l = n.readUshort(r, t); t += 2; var v = n.readUshort(r, t); t += 2; var c = n.readUshort(r, t); t += 2; var p = n.readUshort(r, t); t += 2; var U = n.readUshort(r, t); t += 2; var g, S = h[c], m = d + 12 * s + U; if (0 == u) g = n.readUnicode(r, m, p / 2); else if (3 == u && 0 == l) g = n.readUnicode(r, m, p / 2); else if (0 == l) g = n.readASCII(r, m, p); else if (1 == l) g = n.readUnicode(r, m, p / 2); else if (3 == l) g = n.readUnicode(r, m, p / 2); else { if (1 != u) throw "unknown encoding " + l + ", platformID: " + u; g = n.readASCII(r, m, p), console.debug("reading unknown MAC encoding " + l + " as ASCII"); } var b = "p" + u + "," + v.toString(16); o[b] ?? (o[b] = {}), o[b][void 0 !== S ? S : c] = g, o[b]._lang = v; } for (var y in o) if (null != o[y].postScriptName && 1033 == o[y]._lang) return o[y]; for (var y in o) if (null != o[y].postScriptName && 0 == o[y]._lang) return o[y]; for (var y in o) if (null != o[y].postScriptName && 3084 == o[y]._lang) return o[y]; for (var y in o) if (null != o[y].postScriptName) return o[y]; for (var y in o) { i = y; break; } return console.debug("returning name table with languageID " + o[i]._lang), o[i]; }, e["OS/2"] = {}, e["OS/2"].parse = function(r, t, a) { var n = e._bin.readUshort(r, t); t += 2; var o = {}; if (0 == n) e["OS/2"].version0(r, t, o); else if (1 == n) e["OS/2"].version1(r, t, o); else if (2 == n || 3 == n || 4 == n) e["OS/2"].version2(r, t, o); else { if (5 != n) throw "unknown OS/2 table version: " + n; e["OS/2"].version5(r, t, o); } return o; }, e["OS/2"].version0 = function(r, t, a) { var n = e._bin; return a.xAvgCharWidth = n.readShort(r, t), t += 2, a.usWeightClass = n.readUshort(r, t), t += 2, a.usWidthClass = n.readUshort(r, t), t += 2, a.fsType = n.readUshort(r, t), t += 2, a.ySubscriptXSize = n.readShort(r, t), t += 2, a.ySubscriptYSize = n.readShort(r, t), t += 2, a.ySubscriptXOffset = n.readShort(r, t), t += 2, a.ySubscriptYOffset = n.readShort(r, t), t += 2, a.ySuperscriptXSize = n.readShort(r, t), t += 2, a.ySuperscriptYSize = n.readShort(r, t), t += 2, a.ySuperscriptXOffset = n.readShort(r, t), t += 2, a.ySuperscriptYOffset = n.readShort(r, t), t += 2, a.yStrikeoutSize = n.readShort(r, t), t += 2, a.yStrikeoutPosition = n.readShort(r, t), t += 2, a.sFamilyClass = n.readShort(r, t), t += 2, a.panose = n.readBytes(r, t, 10), t += 10, a.ulUnicodeRange1 = n.readUint(r, t), t += 4, a.ulUnicodeRange2 = n.readUint(r, t), t += 4, a.ulUnicodeRange3 = n.readUint(r, t), t += 4, a.ulUnicodeRange4 = n.readUint(r, t), t += 4, a.achVendID = [ n.readInt8(r, t), n.readInt8(r, t + 1), n.readInt8(r, t + 2), n.readInt8(r, t + 3) ], t += 4, a.fsSelection = n.readUshort(r, t), t += 2, a.usFirstCharIndex = n.readUshort(r, t), t += 2, a.usLastCharIndex = n.readUshort(r, t), t += 2, a.sTypoAscender = n.readShort(r, t), t += 2, a.sTypoDescender = n.readShort(r, t), t += 2, a.sTypoLineGap = n.readShort(r, t), t += 2, a.usWinAscent = n.readUshort(r, t), t += 2, a.usWinDescent = n.readUshort(r, t), t += 2; }, e["OS/2"].version1 = function(r, t, a) { var n = e._bin; return t = e["OS/2"].version0(r, t, a), a.ulCodePageRange1 = n.readUint(r, t), t += 4, a.ulCodePageRange2 = n.readUint(r, t), t += 4; }, e["OS/2"].version2 = function(r, t, a) { var n = e._bin; return t = e["OS/2"].version1(r, t, a), a.sxHeight = n.readShort(r, t), t += 2, a.sCapHeight = n.readShort(r, t), t += 2, a.usDefault = n.readUshort(r, t), t += 2, a.usBreak = n.readUshort(r, t), t += 2, a.usMaxContext = n.readUshort(r, t), t += 2; }, e["OS/2"].version5 = function(r, t, a) { var n = e._bin; return t = e["OS/2"].version2(r, t, a), a.usLowerOpticalPointSize = n.readUshort(r, t), t += 2, a.usUpperOpticalPointSize = n.readUshort(r, t), t += 2; }, e.post = {}, e.post.parse = function(r, t, a) { var n = e._bin, o = {}; return o.version = n.readFixed(r, t), t += 4, o.italicAngle = n.readFixed(r, t), t += 4, o.underlinePosition = n.readShort(r, t), t += 2, o.underlineThickness = n.readShort(r, t), t += 2, o; }, e ??= {}, e.U ?? (e.U = {}), e.U.codeToGlyph = function(r, e) { var t = r.cmap, a = -1; if (null != t.p0e4 ? a = t.p0e4 : null != t.p3e1 ? a = t.p3e1 : null != t.p1e0 ? a = t.p1e0 : null != t.p0e3 && (a = t.p0e3), -1 == a) throw "no familiar platform and encoding!"; var n = t.tables[a]; if (0 == n.format) return e >= n.map.length ? 0 : n.map[e]; if (4 == n.format) { for (var o = -1, s = 0; s < n.endCount.length; s++) if (e <= n.endCount[s]) { o = s; break; } if (-1 == o) return 0; if (n.startCount[o] > e) return 0; return 65535 & (0 != n.idRangeOffset[o] ? n.glyphIdArray[e - n.startCount[o] + (n.idRangeOffset[o] >> 1) - (n.idRangeOffset.length - o)] : e + n.idDelta[o]); } if (12 == n.format) { if (e > n.groups[n.groups.length - 1][1]) return 0; for (s = 0; s < n.groups.length; s++) { var i = n.groups[s]; if (i[0] <= e && e <= i[1]) return i[2] + (e - i[0]); } return 0; } throw "unknown cmap table format " + n.format; }, e.U.glyphToPath = function(r, t) { var a = { cmds: [], crds: [] }; if (r.SVG && r.SVG.entries[t]) { var n = r.SVG.entries[t]; return null == n ? a : ("string" == typeof n && (n = e.SVG.toPath(n), r.SVG.entries[t] = n), n); } if (r.CFF) { var o = { x: 0, y: 0, stack: [], nStems: 0, haveWidth: !1, width: r.CFF.Private ? r.CFF.Private.defaultWidthX : 0, open: !1 }, s = r.CFF, i = r.CFF.Private; if (s.ROS) { for (var h = 0; s.FDSelect[h + 2] <= t;) h += 2; i = s.FDArray[s.FDSelect[h + 1]].Private; } e.U._drawCFF(r.CFF.CharStrings[t], o, s, i, a); } else r.glyf && e.U._drawGlyf(t, r, a); return a; }, e.U._drawGlyf = function(r, t, a) { var n = t.glyf[r]; n ??= t.glyf[r] = e.glyf._parseGlyf(t, r), null != n && (n.noc > -1 ? e.U._simpleGlyph(n, a) : e.U._compoGlyph(n, t, a)); }, e.U._simpleGlyph = function(r, t) { for (var a = 0; a < r.noc; a++) { for (var n = 0 == a ? 0 : r.endPts[a - 1] + 1, o = r.endPts[a], s = n; s <= o; s++) { var i = s == n ? o : s - 1, h = s == o ? n : s + 1, d = 1 & r.flags[s], f = 1 & r.flags[i], u = 1 & r.flags[h], l = r.xs[s], v = r.ys[s]; if (s == n) if (d) { if (!f) { e.U.P.moveTo(t, l, v); continue; } e.U.P.moveTo(t, r.xs[i], r.ys[i]); } else f ? e.U.P.moveTo(t, r.xs[i], r.ys[i]) : e.U.P.moveTo(t, (r.xs[i] + l) / 2, (r.ys[i] + v) / 2); d ? f && e.U.P.lineTo(t, l, v) : u ? e.U.P.qcurveTo(t, l, v, r.xs[h], r.ys[h]) : e.U.P.qcurveTo(t, l, v, (l + r.xs[h]) / 2, (v + r.ys[h]) / 2); } e.U.P.closePath(t); } }, e.U._compoGlyph = function(r, t, a) { for (var n = 0; n < r.parts.length; n++) { var o = { cmds: [], crds: [] }, s = r.parts[n]; e.U._drawGlyf(s.glyphIndex, t, o); for (var i = s.m, h = 0; h < o.crds.length; h += 2) { var d = o.crds[h], f = o.crds[h + 1]; a.crds.push(d * i.a + f * i.b + i.tx), a.crds.push(d * i.c + f * i.d + i.ty); } for (h = 0; h < o.cmds.length; h++) a.cmds.push(o.cmds[h]); } }, e.U._getGlyphClass = function(r, t) { var a = e._lctf.getInterval(t, r); return -1 == a ? 0 : t[a + 2]; }, e.U._applySubs = function(r, t, a, n) { for (var o = r.length - t - 1, s = 0; s < a.tabs.length; s++) if (null != a.tabs[s]) { var i, h = a.tabs[s]; if (!h.coverage || -1 != (i = e._lctf.coverageIndex(h.coverage, r[t]))) { if (1 == a.ltype) r[t], 1 == h.fmt ? r[t] = r[t] + h.delta : r[t] = h.newg[i]; else if (4 == a.ltype) for (var d = h.vals[i], f = 0; f < d.length; f++) { var u = d[f], l = u.chain.length; if (!(l > o)) { for (var v = !0, c = 0, p = 0; p < l; p++) { for (; -1 == r[t + c + (1 + p)];) c++; u.chain[p] != r[t + c + (1 + p)] && (v = !1); } if (v) { r[t] = u.nglyph; for (p = 0; p < l + c; p++) r[t + p + 1] = -1; break; } } } else if (5 == a.ltype && 2 == h.fmt) for (var U = e._lctf.getInterval(h.cDef, r[t]), g = h.cDef[U + 2], S = h.scset[g], m = 0; m < S.length; m++) { var b = S[m], y = b.input; if (!(y.length > o)) { for (v = !0, p = 0; p < y.length; p++) { var F = e._lctf.getInterval(h.cDef, r[t + 1 + p]); if (-1 == U && h.cDef[F + 2] != y[p]) { v = !1; break; } } if (v) { var C = b.substLookupRecords; for (f = 0; f < C.length; f += 2) C[f], C[f + 1]; } } } else if (6 == a.ltype && 3 == h.fmt) { if (!e.U._glsCovered(r, h.backCvg, t - h.backCvg.length)) continue; if (!e.U._glsCovered(r, h.inptCvg, t)) continue; if (!e.U._glsCovered(r, h.ahedCvg, t + h.inptCvg.length)) continue; var _ = h.lookupRec; for (m = 0; m < _.length; m += 2) { U = _[m]; var P = n[_[m + 1]]; e.U._applySubs(r, t + U, P, n); } } } } }, e.U._glsCovered = function(r, t, a) { for (var n = 0; n < t.length; n++) if (-1 == e._lctf.coverageIndex(t[n], r[a + n])) return !1; return !0; }, e.U.glyphsToPath = function(r, t, a) { for (var n = { cmds: [], crds: [] }, o = 0, s = 0; s < t.length; s++) { var i = t[s]; if (-1 != i) { for (var h = s < t.length - 1 && -1 != t[s + 1] ? t[s + 1] : 0, d = e.U.glyphToPath(r, i), f = 0; f < d.crds.length; f += 2) n.crds.push(d.crds[f] + o), n.crds.push(d.crds[f + 1]); a && n.cmds.push(a); for (f = 0; f < d.cmds.length; f++) n.cmds.push(d.cmds[f]); a && n.cmds.push("X"), o += r.hmtx.aWidth[i], s < t.length - 1 && (o += e.U.getPairAdjustment(r, i, h)); } } return n; }, e.U.P = {}, e.U.P.moveTo = function(r, e, t) { r.cmds.push("M"), r.crds.push(e, t); }, e.U.P.lineTo = function(r, e, t) { r.cmds.push("L"), r.crds.push(e, t); }, e.U.P.curveTo = function(r, e, t, a, n, o, s) { r.cmds.push("C"), r.crds.push(e, t, a, n, o, s); }, e.U.P.qcurveTo = function(r, e, t, a, n) { r.cmds.push("Q"), r.crds.push(e, t, a, n); }, e.U.P.closePath = function(r) { r.cmds.push("Z"); }, e.U._drawCFF = function(r, t, a, n, o) { for (var s = t.stack, i = t.nStems, h = t.haveWidth, d = t.width, f = t.open, u = 0, l = t.x, v = t.y, c = 0, p = 0, U = 0, g = 0, S = 0, m = 0, b = 0, y = 0, F = 0, C = 0, _ = { val: 0, size: 0 }; u < r.length;) { e.CFF.getCharString(r, u, _); var P = _.val; if (u += _.size, "o1" == P || "o18" == P) s.length % 2 != 0 && !h && (d = s.shift() + n.nominalWidthX), i += s.length >> 1, s.length = 0, h = !0; else if ("o3" == P || "o23" == P) s.length % 2 != 0 && !h && (d = s.shift() + n.nominalWidthX), i += s.length >> 1, s.length = 0, h = !0; else if ("o4" == P) s.length > 1 && !h && (d = s.shift() + n.nominalWidthX, h = !0), f && e.U.P.closePath(o), v += s.pop(), e.U.P.moveTo(o, l, v), f = !0; else if ("o5" == P) for (; s.length > 0;) l += s.shift(), v += s.shift(), e.U.P.lineTo(o, l, v); else if ("o6" == P || "o7" == P) for (var x = s.length, I = "o6" == P, w = 0; w < x; w++) { var k = s.shift(); I ? l += k : v += k, I = !I, e.U.P.lineTo(o, l, v); } else if ("o8" == P || "o24" == P) { x = s.length; for (var G = 0; G + 6 <= x;) c = l + s.shift(), p = v + s.shift(), U = c + s.shift(), g = p + s.shift(), l = U + s.shift(), v = g + s.shift(), e.U.P.curveTo(o, c, p, U, g, l, v), G += 6; "o24" == P && (l += s.shift(), v += s.shift(), e.U.P.lineTo(o, l, v)); } else { if ("o11" == P) break; if ("o1234" == P || "o1235" == P || "o1236" == P || "o1237" == P) "o1234" == P && (p = v, U = (c = l + s.shift()) + s.shift(), C = g = p + s.shift(), m = g, y = v, l = (b = (S = (F = U + s.shift()) + s.shift()) + s.shift()) + s.shift(), e.U.P.curveTo(o, c, p, U, g, F, C), e.U.P.curveTo(o, S, m, b, y, l, v)), "o1235" == P && (c = l + s.shift(), p = v + s.shift(), U = c + s.shift(), g = p + s.shift(), F = U + s.shift(), C = g + s.shift(), S = F + s.shift(), m = C + s.shift(), b = S + s.shift(), y = m + s.shift(), l = b + s.shift(), v = y + s.shift(), s.shift(), e.U.P.curveTo(o, c, p, U, g, F, C), e.U.P.curveTo(o, S, m, b, y, l, v)), "o1236" == P && (c = l + s.shift(), p = v + s.shift(), U = c + s.shift(), C = g = p + s.shift(), m = g, b = (S = (F = U + s.shift()) + s.shift()) + s.shift(), y = m + s.shift(), l = b + s.shift(), e.U.P.curveTo(o, c, p, U, g, F, C), e.U.P.curveTo(o, S, m, b, y, l, v)), "o1237" == P && (c = l + s.shift(), p = v + s.shift(), U = c + s.shift(), g = p + s.shift(), F = U + s.shift(), C = g + s.shift(), S = F + s.shift(), m = C + s.shift(), b = S + s.shift(), y = m + s.shift(), Math.abs(b - l) > Math.abs(y - v) ? l = b + s.shift() : v = y + s.shift(), e.U.P.curveTo(o, c, p, U, g, F, C), e.U.P.curveTo(o, S, m, b, y, l, v)); else if ("o14" == P) { if (s.length > 0 && !h && (d = s.shift() + a.nominalWidthX, h = !0), 4 == s.length) { var O = s.shift(), T = s.shift(), D = s.shift(), B = s.shift(), A = e.CFF.glyphBySE(a, D), R = e.CFF.glyphBySE(a, B); e.U._drawCFF(a.CharStrings[A], t, a, n, o), t.x = O, t.y = T, e.U._drawCFF(a.CharStrings[R], t, a, n, o); } f && (e.U.P.closePath(o), f = !1); } else if ("o19" == P || "o20" == P) s.length % 2 != 0 && !h && (d = s.shift() + n.nominalWidthX), i += s.length >> 1, s.length = 0, h = !0, u += i + 7 >> 3; else if ("o21" == P) s.length > 2 && !h && (d = s.shift() + n.nominalWidthX, h = !0), v += s.pop(), l += s.pop(), f && e.U.P.closePath(o), e.U.P.moveTo(o, l, v), f = !0; else if ("o22" == P) s.length > 1 && !h && (d = s.shift() + n.nominalWidthX, h = !0), l += s.pop(), f && e.U.P.closePath(o), e.U.P.moveTo(o, l, v), f = !0; else if ("o25" == P) { for (; s.length > 6;) l += s.shift(), v += s.shift(), e.U.P.lineTo(o, l, v); c = l + s.shift(), p = v + s.shift(), U = c + s.shift(), g = p + s.shift(), l = U + s.shift(), v = g + s.shift(), e.U.P.curveTo(o, c, p, U, g, l, v); } else if ("o26" == P) for (s.length % 2 && (l += s.shift()); s.length > 0;) c = l, p = v + s.shift(), l = U = c + s.shift(), v = (g = p + s.shift()) + s.shift(), e.U.P.curveTo(o, c, p, U, g, l, v); else if ("o27" == P) for (s.length % 2 && (v += s.shift()); s.length > 0;) p = v, U = (c = l + s.shift()) + s.shift(), g = p + s.shift(), l = U + s.shift(), v = g, e.U.P.curveTo(o, c, p, U, g, l, v); else if ("o10" == P || "o29" == P) { var L = "o10" == P ? n : a; if (0 == s.length) console.debug("error: empty stack"); else { var W = s.pop(), M = L.Subrs[W + L.Bias]; t.x = l, t.y = v, t.nStems = i, t.haveWidth = h, t.width = d, t.open = f, e.U._drawCFF(M, t, a, n, o), l = t.x, v = t.y, i = t.nStems, h = t.haveWidth, d = t.width, f = t.open; } } else if ("o30" == P || "o31" == P) { var V = s.length, E = (G = 0, "o31" == P); for (G += V - (x = -3 & V); G < x;) E ? (p = v, U = (c = l + s.shift()) + s.shift(), v = (g = p + s.shift()) + s.shift(), x - G == 5 ? (l = U + s.shift(), G++) : l = U, E = !1) : (c = l, p = v + s.shift(), U = c + s.shift(), g = p + s.shift(), l = U + s.shift(), x - G == 5 ? (v = g + s.shift(), G++) : v = g, E = !0), e.U.P.curveTo(o, c, p, U, g, l, v), G += 4; } else { if ("o" == (P + "").charAt(0)) throw console.debug("Unknown operation: " + P, r), P; s.push(P); } } } t.x = l, t.y = v, t.nStems = i, t.haveWidth = h, t.width = d, t.open = f; }; var t = e, a = { Typr: t }; return r.Typr = t, r.default = a, Object.defineProperty(r, "__esModule", { value: !0 }), r; }({}).Typr; } /*! Custom bundle of woff2otf (https://github.com/arty-name/woff2otf) with fflate (https://github.com/101arrowz/fflate) for use in Troika text rendering. Original licenses apply: - fflate: https://github.com/101arrowz/fflate/blob/master/LICENSE (MIT) - woff2otf.js: https://github.com/arty-name/woff2otf/blob/master/woff2otf.js (Apache2) */ function woff2otfFactory() { return function(r) { var e = Uint8Array, n = Uint16Array, t = Uint32Array, a = new e([ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0 ]), i = new e([ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 ]), o = new e([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]), f = function(r, e) { for (var a = new n(31), i = 0; i < 31; ++i) a[i] = e += 1 << r[i - 1]; var o = new t(a[30]); for (i = 1; i < 30; ++i) for (var f = a[i]; f < a[i + 1]; ++f) o[f] = f - a[i] << 5 | i; return [a, o]; }, u = f(a, 2), v = u[0], s = u[1]; v[28] = 258, s[258] = 28; for (var l = f(i, 0)[0], c = new n(32768), g = 0; g < 32768; ++g) { var h = (43690 & g) >>> 1 | (21845 & g) << 1; h = (61680 & (h = (52428 & h) >>> 2 | (13107 & h) << 2)) >>> 4 | (3855 & h) << 4, c[g] = ((65280 & h) >>> 8 | (255 & h) << 8) >>> 1; } var w = function(r, e, t) { for (var a = r.length, i = 0, o = new n(e); i < a; ++i) ++o[r[i] - 1]; var f, u = new n(e); for (i = 0; i < e; ++i) u[i] = u[i - 1] + o[i - 1] << 1; if (t) { f = new n(1 << e); var v = 15 - e; for (i = 0; i < a; ++i) if (r[i]) for (var s = i << 4 | r[i], l = e - r[i], g = u[r[i] - 1]++ << l, h = g | (1 << l) - 1; g <= h; ++g) f[c[g] >>> v] = s; } else for (f = new n(a), i = 0; i < a; ++i) r[i] && (f[i] = c[u[r[i] - 1]++] >>> 15 - r[i]); return f; }, d = new e(288); for (g = 0; g < 144; ++g) d[g] = 8; for (g = 144; g < 256; ++g) d[g] = 9; for (g = 256; g < 280; ++g) d[g] = 7; for (g = 280; g < 288; ++g) d[g] = 8; var m = new e(32); for (g = 0; g < 32; ++g) m[g] = 5; var b = w(d, 9, 1), p = w(m, 5, 1), y = function(r) { for (var e = r[0], n = 1; n < r.length; ++n) r[n] > e && (e = r[n]); return e; }, L = function(r, e, n) { var t = e / 8 | 0; return (r[t] | r[t + 1] << 8) >> (7 & e) & n; }, U = function(r, e) { var n = e / 8 | 0; return (r[n] | r[n + 1] << 8 | r[n + 2] << 16) >> (7 & e); }, k = [ "unexpected EOF", "invalid block type", "invalid length/literal", "invalid distance", "stream finished", "no stream handler", , "no callback", "invalid UTF-8 data", "extra field too long", "date not in range 1980-2099", "filename too long", "stream finishing", "invalid zip data" ], T = function(r, e, n) { var t = new Error(e || k[r]); if (t.code = r, Error.captureStackTrace && Error.captureStackTrace(t, T), !n) throw t; return t; }, O = function(r, f, u) { var s = r.length; if (!s || u && !u.l && s < 5) return f || new e(0); var c = !f || u, g = !u || u.i; u || (u = {}), f || (f = new e(3 * s)); var h, d = function(r) { var n = f.length; if (r > n) { var t = new e(Math.max(2 * n, r)); t.set(f), f = t; } }, m = u.f || 0, k = u.p || 0, O = u.b || 0, A = u.l, x = u.d, E = u.m, D = u.n, M = 8 * s; do { if (!A) { u.f = m = L(r, k, 1); var S = L(r, k + 1, 3); if (k += 3, !S) { var V = r[(I = ((h = k) / 8 | 0) + (7 & h && 1) + 4) - 4] | r[I - 3] << 8, _ = I + V; if (_ > s) { g && T(0); break; } c && d(O + V), f.set(r.subarray(I, _), O), u.b = O += V, u.p = k = 8 * _; continue; } if (1 == S) A = b, x = p, E = 9, D = 5; else if (2 == S) { var j = L(r, k, 31) + 257, z = L(r, k + 10, 15) + 4, C = j + L(r, k + 5, 31) + 1; k += 14; for (var F = new e(C), P = new e(19), q = 0; q < z; ++q) P[o[q]] = L(r, k + 3 * q, 7); k += 3 * z; var B = y(P), G = (1 << B) - 1, H = w(P, B, 1); for (q = 0; q < C;) { var I, J = H[L(r, k, G)]; if (k += 15 & J, (I = J >>> 4) < 16) F[q++] = I; else { var K = 0, N = 0; for (16 == I ? (N = 3 + L(r, k, 3), k += 2, K = F[q - 1]) : 17 == I ? (N = 3 + L(r, k, 7), k += 3) : 18 == I && (N = 11 + L(r, k, 127), k += 7); N--;) F[q++] = K; } } var Q = F.subarray(0, j), R = F.subarray(j); E = y(Q), D = y(R), A = w(Q, E, 1), x = w(R, D, 1); } else T(1); if (k > M) { g && T(0); break; } } c && d(O + 131072); for (var W = (1 << E) - 1, X = (1 << D) - 1, Y = k;; Y = k) { var Z = (K = A[U(r, k) & W]) >>> 4; if ((k += 15 & K) > M) { g && T(0); break; } if (K || T(2), Z < 256) f[O++] = Z; else { if (256 == Z) { Y = k, A = null; break; } var $ = Z - 254; if (Z > 264) { var rr = a[q = Z - 257]; $ = L(r, k, (1 << rr) - 1) + v[q], k += rr; } var er = x[U(r, k) & X], nr = er >>> 4; er || T(3), k += 15 & er; R = l[nr]; if (nr > 3) { rr = i[nr]; R += U(r, k) & (1 << rr) - 1, k += rr; } if (k > M) { g && T(0); break; } c && d(O + 131072); for (var tr = O + $; O < tr; O += 4) f[O] = f[O - R], f[O + 1] = f[O + 1 - R], f[O + 2] = f[O + 2 - R], f[O + 3] = f[O + 3 - R]; O = tr; } } u.l = A, u.p = Y, u.b = O, A && (m = 1, u.m = E, u.d = x, u.n = D); } while (!m); return O == f.length ? f : function(r, a, i) { (null == a || a < 0) && (a = 0), (null == i || i > r.length) && (i = r.length); var o = new (r instanceof n ? n : r instanceof t ? t : e)(i - a); return o.set(r.subarray(a, i)), o; }(f, 0, O); }, A = new e(0); var x = "undefined" != typeof TextDecoder && new TextDecoder(); try { x.decode(A, { stream: !0 }); } catch (r) {} return r.convert_streams = function(r) { var e = new DataView(r), n = 0; function t() { var r = e.getUint16(n); return n += 2, r; } function a() { var r = e.getUint32(n); return n += 4, r; } function i(r) { m.setUint16(b, r), b += 2; } function o(r) { m.setUint32(b, r), b += 4; } for (var f = { signature: a(), flavor: a(), length: a(), numTables: t(), reserved: t(), totalSfntSize: a(), majorVersion: t(), minorVersion: t(), metaOffset: a(), metaLength: a(), metaOrigLength: a(), privOffset: a(), privLength: a() }, u = 0; Math.pow(2, u) <= f.numTables;) u++; u--; for (var v = 16 * Math.pow(2, u), s = 16 * f.numTables - v, l = 12, c = [], g = 0; g < f.numTables; g++) c.push({ tag: a(), offset: a(), compLength: a(), origLength: a(), origChecksum: a() }), l += 16; var h, w = new Uint8Array(12 + 16 * c.length + c.reduce((function(r, e) { return r + e.origLength + 4; }), 0)), d = w.buffer, m = new DataView(d), b = 0; return o(f.flavor), i(f.numTables), i(v), i(u), i(s), c.forEach((function(r) { o(r.tag), o(r.origChecksum), o(l), o(r.origLength), r.outOffset = l, (l += r.origLength) % 4 != 0 && (l += 4 - l % 4); })), c.forEach((function(e) { var n, t = r.slice(e.offset, e.offset + e.compLength); if (e.compLength != e.origLength) { var a = new Uint8Array(e.origLength); n = new Uint8Array(t, 2), O(n, a); } else a = new Uint8Array(t); w.set(a, e.outOffset); var i = 0; (l = e.outOffset + e.origLength) % 4 != 0 && (i = 4 - l % 4), w.set(new Uint8Array(i).buffer, e.outOffset + e.origLength), h = l + i; })), d.slice(0, h); }, Object.defineProperty(r, "__esModule", { value: !0 }), r; }({}).convert_streams; } /** * A factory wrapper parsing a font file using Typr. * Also adds support for WOFF files (not WOFF2). */ /** * @typedef ParsedFont * @property {number} ascender * @property {number} descender * @property {number} xHeight * @property {(number) => boolean} supportsCodePoint * @property {(text:string, fontSize:number, letterSpacing:number, callback) => number} forEachGlyph * @property {number} lineGap * @property {number} capHeight * @property {number} unitsPerEm */ /** * @typedef {(buffer: ArrayBuffer) => ParsedFont} FontParser */ /** * @returns {FontParser} */ function parserFactory(Typr, woff2otf) { const cmdArgLengths = { M: 2, L: 2, Q: 4, C: 6, Z: 0 }; const joiningTypeRawData = { "C": "18g,ca,368,1kz", "D": "17k,6,2,2+4,5+c,2+6,2+1,10+1,9+f,j+11,2+1,a,2,2+1,15+2,3,j+2,6+3,2+8,2,2,2+1,w+a,4+e,3+3,2,3+2,3+5,23+w,2f+4,3,2+9,2,b,2+3,3,1k+9,6+1,3+1,2+2,2+d,30g,p+y,1,1+1g,f+x,2,sd2+1d,jf3+4,f+3,2+4,2+2,b+3,42,2,4+2,2+1,2,3,t+1,9f+w,2,el+2,2+g,d+2,2l,2+1,5,3+1,2+1,2,3,6,16wm+1v", "R": "17m+3,2,2,6+3,m,15+2,2+2,h+h,13,3+8,2,2,3+1,2,p+1,x,5+4,5,a,2,2,3,u,c+2,g+1,5,2+1,4+1,5j,6+1,2,b,2+2,f,2+1,1s+2,2,3+1,7,1ez0,2,2+1,4+4,b,4,3,b,42,2+2,4,3,2+1,2,o+3,ae,ep,x,2o+2,3+1,3,5+1,6", "L": "x9u,jff,a,fd,jv", "T": "4t,gj+33,7o+4,1+1,7c+18,2,2+1,2+1,2,21+a,2,1b+k,h,2u+6,3+5,3+1,2+3,y,2,v+q,2k+a,1n+8,a,p+3,2+8,2+2,2+4,18+2,3c+e,2+v,1k,2,5+7,5,4+6,b+1,u,1n,5+3,9,l+1,r,3+1,1m,5+1,5+1,3+2,4,v+1,4,c+1,1m,5+4,2+1,5,l+1,n+5,2,1n,3,2+3,9,8+1,c+1,v,1q,d,1f,4,1m+2,6+2,2+3,8+1,c+1,u,1n,3,7,6+1,l+1,t+1,1m+1,5+3,9,l+1,u,21,8+2,2,2j,3+6,d+7,2r,3+8,c+5,23+1,s,2,2,1k+d,2+4,2+1,6+a,2+z,a,2v+3,2+5,2+1,3+1,q+1,5+2,h+3,e,3+1,7,g,jk+2,qb+2,u+2,u+1,v+1,1t+1,2+6,9,3+a,a,1a+2,3c+1,z,3b+2,5+1,a,7+2,64+1,3,1n,2+6,2,2,3+7,7+9,3,1d+d,1,1+1,1s+3,1d,2+4,2,6,15+8,d+1,x+3,3+1,2+2,1l,2+1,4,2+2,1n+7,3+1,49+2,2+c,2+6,5,7,4+1,5j+1l,2+4,ek,3+1,r+4,1e+4,6+5,2p+c,1+3,1,1+2,1+b,2db+2,3y,2p+v,ff+3,30+1,n9x,1+2,2+9,x+1,29+1,7l,4,5,q+1,6,48+1,r+h,e,13+7,q+a,1b+2,1d,3+3,3+1,14,1w+5,3+1,3+1,d,9,1c,1g,2+2,3+1,6+1,2,17+1,9,6n,3,5,fn5,ki+f,h+f,5s,6y+2,ea,6b,46+4,1af+2,2+1,6+3,15+2,5,4m+1,fy+3,as+1,4a+a,4x,1j+e,1l+2,1e+3,3+1,1y+2,11+4,2+7,1r,d+1,1h+8,b+3,3,2o+2,3,2+1,7,4h,4+7,m+1,1m+1,4,12+6,4+4,5g+7,3+2,2,o,2d+5,2,5+1,2+1,6n+3,7+1,2+1,s+1,2e+7,3,2+1,2z,2,3+5,2,2u+2,3+3,2+4,78+8,2+1,75+1,2,5,41+3,3+1,5,x+9,15+5,3+3,9,a+5,3+2,1b+c,2+1,bb+6,2+5,2,2b+l,3+6,2+1,2+1,3f+5,4,2+1,2+6,2,21+1,4,2,9o+1,470+8,at4+4,1o+6,t5,1s+3,2a,f5l+1,2+3,43o+2,a+7,1+7,3+6,v+3,45+2,1j0+1i,5+1d,9,f,n+4,2+e,11t+6,2+g,3+6,2+1,2+4,7a+6,c6+3,15t+6,32+6,1,gzau,v+2n,3l+6n" }; const JT_LEFT = 1, JT_RIGHT = 2, JT_DUAL = 4, JT_TRANSPARENT = 8, JT_JOIN_CAUSING = 16, JT_NON_JOINING = 32; let joiningTypeMap; function getCharJoiningType(ch) { if (!joiningTypeMap) { const m = { R: JT_RIGHT, L: JT_LEFT, D: JT_DUAL, C: JT_JOIN_CAUSING, U: JT_NON_JOINING, T: JT_TRANSPARENT }; joiningTypeMap = /* @__PURE__ */ new Map(); for (let type in joiningTypeRawData) { let lastCode = 0; joiningTypeRawData[type].split(",").forEach((range) => { let [skip, step] = range.split("+"); skip = parseInt(skip, 36); step = step ? parseInt(step, 36) : 0; joiningTypeMap.set(lastCode += skip, m[type]); for (let i = step; i--;) joiningTypeMap.set(++lastCode, m[type]); }); } } return joiningTypeMap.get(ch) || JT_NON_JOINING; } const ISOL = 1, INIT = 2, FINA = 3, MEDI = 4; const formsToFeatures = [ null, "isol", "init", "fina", "medi" ]; function detectJoiningForms(str) { const joiningForms = new Uint8Array(str.length); let prevJoiningType = JT_NON_JOINING; let prevForm = ISOL; let prevIndex = -1; for (let i = 0; i < str.length; i++) { const code = str.codePointAt(i); let joiningType = getCharJoiningType(code) | 0; let form = ISOL; if (joiningType & JT_TRANSPARENT) continue; if (prevJoiningType & 21) { if (joiningType & 22) { form = FINA; if (prevForm === ISOL || prevForm === FINA) joiningForms[prevIndex]++; } else if (joiningType & 33) { if (prevForm === INIT || prevForm === MEDI) joiningForms[prevIndex]--; } } else if (prevJoiningType & 34) { if (prevForm === INIT || prevForm === MEDI) joiningForms[prevIndex]--; } prevForm = joiningForms[i] = form; prevJoiningType = joiningType; prevIndex = i; if (code > 65535) i++; } return joiningForms; } function stringToGlyphs(font, str) { const glyphIds = []; for (let i = 0; i < str.length; i++) { const cc = str.codePointAt(i); if (cc > 65535) i++; glyphIds.push(Typr.U.codeToGlyph(font, cc)); } const gsub = font["GSUB"]; if (gsub) { const { lookupList, featureList } = gsub; let joiningForms; const supportedFeatures = /^(rlig|liga|mset|isol|init|fina|medi|half|pres|blws|ccmp)$/; const usedLookups = []; featureList.forEach((feature) => { if (supportedFeatures.test(feature.tag)) for (let ti = 0; ti < feature.tab.length; ti++) { if (usedLookups[feature.tab[ti]]) continue; usedLookups[feature.tab[ti]] = true; const tab = lookupList[feature.tab[ti]]; const isJoiningFeature = /^(isol|init|fina|medi)$/.test(feature.tag); if (isJoiningFeature && !joiningForms) joiningForms = detectJoiningForms(str); for (let ci = 0; ci < glyphIds.length; ci++) if (!joiningForms || !isJoiningFeature || formsToFeatures[joiningForms[ci]] === feature.tag) Typr.U._applySubs(glyphIds, ci, tab, lookupList); } }); } return glyphIds; } function calcGlyphPositions(font, glyphIds) { const positions = new Int16Array(glyphIds.length * 3); let glyphIndex = 0; for (; glyphIndex < glyphIds.length; glyphIndex++) { const glyphId = glyphIds[glyphIndex]; if (glyphId === -1) continue; positions[glyphIndex * 3 + 2] = font.hmtx.aWidth[glyphId]; const gpos = font.GPOS; if (gpos) { const llist = gpos.lookupList; for (let i = 0; i < llist.length; i++) { const lookup = llist[i]; for (let j = 0; j < lookup.tabs.length; j++) { const tab = lookup.tabs[j]; if (lookup.ltype === 1) { if (Typr._lctf.coverageIndex(tab.coverage, glyphId) !== -1 && tab.pos) { applyValueRecord(tab.pos, glyphIndex); break; } } else if (lookup.ltype === 2) { let adj = null; let prevGlyphIndex = getPrevGlyphIndex(); if (prevGlyphIndex !== -1) { const coverageIndex = Typr._lctf.coverageIndex(tab.coverage, glyphIds[prevGlyphIndex]); if (coverageIndex !== -1) { if (tab.fmt === 1) { const right = tab.pairsets[coverageIndex]; for (let k = 0; k < right.length; k++) if (right[k].gid2 === glyphId) adj = right[k]; } else if (tab.fmt === 2) { const c1 = Typr.U._getGlyphClass(glyphIds[prevGlyphIndex], tab.classDef1); const c2 = Typr.U._getGlyphClass(glyphId, tab.classDef2); adj = tab.matrix[c1][c2]; } if (adj) { if (adj.val1) applyValueRecord(adj.val1, prevGlyphIndex); if (adj.val2) applyValueRecord(adj.val2, glyphIndex); break; } } } } else if (lookup.ltype === 4) { const markArrIndex = Typr._lctf.coverageIndex(tab.markCoverage, glyphId); if (markArrIndex !== -1) { const baseGlyphIndex = getPrevGlyphIndex(isBaseGlyph); const baseArrIndex = baseGlyphIndex === -1 ? -1 : Typr._lctf.coverageIndex(tab.baseCoverage, glyphIds[baseGlyphIndex]); if (baseArrIndex !== -1) { const markRecord = tab.markArray[markArrIndex]; const baseAnchor = tab.baseArray[baseArrIndex][markRecord.markClass]; positions[glyphIndex * 3] = baseAnchor.x - markRecord.x + positions[baseGlyphIndex * 3] - positions[baseGlyphIndex * 3 + 2]; positions[glyphIndex * 3 + 1] = baseAnchor.y - markRecord.y + positions[baseGlyphIndex * 3 + 1]; break; } } } else if (lookup.ltype === 6) { const mark1ArrIndex = Typr._lctf.coverageIndex(tab.mark1Coverage, glyphId); if (mark1ArrIndex !== -1) { const prevGlyphIndex = getPrevGlyphIndex(); if (prevGlyphIndex !== -1) { const prevGlyphId = glyphIds[prevGlyphIndex]; if (getGlyphClass(font, prevGlyphId) === 3) { const mark2ArrIndex = Typr._lctf.coverageIndex(tab.mark2Coverage, prevGlyphId); if (mark2ArrIndex !== -1) { const mark1Record = tab.mark1Array[mark1ArrIndex]; const mark2Anchor = tab.mark2Array[mark2ArrIndex][mark1Record.markClass]; positions[glyphIndex * 3] = mark2Anchor.x - mark1Record.x + positions[prevGlyphIndex * 3] - positions[prevGlyphIndex * 3 + 2]; positions[glyphIndex * 3 + 1] = mark2Anchor.y - mark1Record.y + positions[prevGlyphIndex * 3 + 1]; break; } } } } } } } } else if (font.kern && !font.cff) { const prevGlyphIndex = getPrevGlyphIndex(); if (prevGlyphIndex !== -1) { const ind1 = font.kern.glyph1.indexOf(glyphIds[prevGlyphIndex]); if (ind1 !== -1) { const ind2 = font.kern.rval[ind1].glyph2.indexOf(glyphId); if (ind2 !== -1) positions[prevGlyphIndex * 3 + 2] += font.kern.rval[ind1].vals[ind2]; } } } } return positions; function getPrevGlyphIndex(filter) { for (let i = glyphIndex - 1; i >= 0; i--) if (glyphIds[i] !== -1 && (!filter || filter(glyphIds[i]))) return i; return -1; } function isBaseGlyph(glyphId) { return getGlyphClass(font, glyphId) === 1; } function applyValueRecord(source, gi) { for (let i = 0; i < 3; i++) positions[gi * 3 + i] += source[i] || 0; } } function getGlyphClass(font, glyphId) { const classDef = font.GDEF && font.GDEF.glyphClassDef; return classDef ? Typr.U._getGlyphClass(glyphId, classDef) : 0; } function firstNum(...args) { for (let i = 0; i < args.length; i++) if (typeof args[i] === "number") return args[i]; } /** * @returns ParsedFont */ function wrapFontObj(typrFont) { const glyphMap = Object.create(null); const os2 = typrFont["OS/2"]; const hhea = typrFont.hhea; const unitsPerEm = typrFont.head.unitsPerEm; const ascender = firstNum(os2 && os2.sTypoAscender, hhea && hhea.ascender, unitsPerEm); /** @type ParsedFont */ const fontObj = { unitsPerEm, ascender, descender: firstNum(os2 && os2.sTypoDescender, hhea && hhea.descender, 0), capHeight: firstNum(os2 && os2.sCapHeight, ascender), xHeight: firstNum(os2 && os2.sxHeight, ascender), lineGap: firstNum(os2 && os2.sTypoLineGap, hhea && hhea.lineGap), supportsCodePoint(code) { return Typr.U.codeToGlyph(typrFont, code) > 0; }, forEachGlyph(text, fontSize, letterSpacing, callback) { let penX = 0; const fontScale = 1 / fontObj.unitsPerEm * fontSize; const glyphIds = stringToGlyphs(typrFont, text); let charIndex = 0; const positions = calcGlyphPositions(typrFont, glyphIds); glyphIds.forEach((glyphId, i) => { if (glyphId !== -1) { let glyphObj = glyphMap[glyphId]; if (!glyphObj) { const { cmds, crds } = Typr.U.glyphToPath(typrFont, glyphId); let path = ""; let crdsIdx = 0; for (let i = 0, len = cmds.length; i < len; i++) { const numArgs = cmdArgLengths[cmds[i]]; path += cmds[i]; for (let j = 1; j <= numArgs; j++) path += (j > 1 ? "," : "") + crds[crdsIdx++]; } let xMin, yMin, xMax, yMax; if (crds.length) { xMin = yMin = Infinity; xMax = yMax = -Infinity; for (let i = 0, len = crds.length; i < len; i += 2) { let x = crds[i]; let y = crds[i + 1]; if (x < xMin) xMin = x; if (y < yMin) yMin = y; if (x > xMax) xMax = x; if (y > yMax) yMax = y; } } else xMin = xMax = yMin = yMax = 0; glyphObj = glyphMap[glyphId] = { index: glyphId, advanceWidth: typrFont.hmtx.aWidth[glyphId], xMin, yMin, xMax, yMax, path }; } callback.call(null, glyphObj, penX + positions[i * 3] * fontScale, positions[i * 3 + 1] * fontScale, charIndex); penX += positions[i * 3 + 2] * fontScale; if (letterSpacing) penX += letterSpacing * fontSize; } charIndex += text.codePointAt(charIndex) > 65535 ? 2 : 1; }); return penX; } }; return fontObj; } /** * @type FontParser */ return function parse(buffer) { const peek = new Uint8Array(buffer, 0, 4); const tag = Typr._bin.readASCII(peek, 0, 4); if (tag === "wOFF") buffer = woff2otf(buffer); else if (tag === "wOF2") throw new Error("woff2 fonts not supported"); return wrapFontObj(Typr.parse(buffer)[0]); }; } var workerModule = /*#__PURE__*/ defineWorkerModule({ name: "Typr Font Parser", dependencies: [ typrFactory, woff2otfFactory, parserFactory ], init(typrFactory, woff2otfFactory, parserFactory) { return parserFactory(typrFactory(), woff2otfFactory()); } }); /*! Custom bundle of @unicode-font-resolver/client v1.0.2 (https://github.com/lojjic/unicode-font-resolver) for use in Troika text rendering. Original MIT license applies */ function unicodeFontResolverClientFactory() { return function(t) { var n = function() { this.buckets = /* @__PURE__ */ new Map(); }; n.prototype.add = function(t) { var n = t >> 5; this.buckets.set(n, (this.buckets.get(n) || 0) | 1 << (31 & t)); }, n.prototype.has = function(t) { var n = this.buckets.get(t >> 5); return void 0 !== n && 0 != (n & 1 << (31 & t)); }, n.prototype.serialize = function() { var t = []; return this.buckets.forEach((function(n, r) { t.push((+r).toString(36) + ":" + n.toString(36)); })), t.join(","); }, n.prototype.deserialize = function(t) { var n = this; this.buckets.clear(), t.split(",").forEach((function(t) { var r = t.split(":"); n.buckets.set(parseInt(r[0], 36), parseInt(r[1], 36)); })); }; var r = Math.pow(2, 8), e = r - 1, o = ~e; function a(t) { var n = function(t) { return t & o; }(t).toString(16), e = function(t) { return (t & o) + r - 1; }(t).toString(16); return "codepoint-index/plane" + (t >> 16) + "/" + n + "-" + e + ".json"; } function i(t, n) { var r = t & e, o = n.codePointAt(r / 6 | 0); return 0 != ((o = (o || 48) - 48) & 1 << r % 6); } function u(t, n) { var r; (r = t, r.replace(/U\+/gi, "").replace(/^,+|,+$/g, "").split(/,+/).map((function(t) { return t.split("-").map((function(t) { return parseInt(t.trim(), 16); })); }))).forEach((function(t) { var r = t[0], e = t[1]; void 0 === e && (e = r), n(r, e); })); } function c(t, n) { u(t, (function(t, r) { for (var e = t; e <= r; e++) n(e); })); } var s = {}, f = {}, l = /* @__PURE__ */ new WeakMap(), v = "https://cdn.jsdelivr.net/gh/lojjic/unicode-font-resolver@v1.0.1/packages/data"; function d(t) { var r = l.get(t); return r || (r = new n(), c(t.ranges, (function(t) { return r.add(t); })), l.set(t, r)), r; } var h, p = /* @__PURE__ */ new Map(); function g(t, n, r) { return t[n] ? n : t[r] ? r : function(t) { for (var n in t) return n; }(t); } function w(t, n) { var r = n; if (!t.includes(r)) { r = Infinity; for (var e = 0; e < t.length; e++) Math.abs(t[e] - n) < Math.abs(r - n) && (r = t[e]); } return r; } function k(t) { return h || (h = /* @__PURE__ */ new Set(), c("9-D,20,85,A0,1680,2000-200A,2028-202F,205F,3000", (function(t) { h.add(t); }))), h.has(t); } return t.CodePointSet = n, t.clearCache = function() { s = {}, f = {}; }, t.getFontsForString = function(t, n) { void 0 === n && (n = {}); var r, e = n.lang; void 0 === e && (e = /\p{Script=Hangul}/u.test(r = t) ? "ko" : /\p{Script=Hiragana}|\p{Script=Katakana}/u.test(r) ? "ja" : "en"); var o = n.category; void 0 === o && (o = "sans-serif"); var u = n.style; void 0 === u && (u = "normal"); var c = n.weight; void 0 === c && (c = 400); var l = (n.dataUrl || v).replace(/\/$/g, ""), h = /* @__PURE__ */ new Map(), y = new Uint8Array(t.length), b = {}, m = {}, A = new Array(t.length), S = /* @__PURE__ */ new Map(), j = !1; function M(t) { var n = p.get(t); return n || (n = fetch(l + "/" + t).then((function(t) { if (!t.ok) throw new Error(t.statusText); return t.json().then((function(t) { if (!Array.isArray(t) || 1 !== t[0]) throw new Error("Incorrect schema version; need 1, got " + t[0]); return t[1]; })); })).catch((function(n) { if (l !== v) return j || (console.error("unicode-font-resolver: Failed loading from dataUrl \"" + l + "\", trying default CDN. " + n.message), j = !0), l = v, p.delete(t), M(t); throw n; })), p.set(t, n)), n; } for (var P = function(n) { var r = t.codePointAt(n), e = a(r); A[n] = e, s[e] || S.has(e) || S.set(e, M(e).then((function(t) { s[e] = t; }))), r > 65535 && (n++, E = n); }, E = 0; E < t.length; E++) P(E); return Promise.all(S.values()).then((function() { S.clear(); for (var n = function(n) { var o = t.codePointAt(n), a = null, u = s[A[n]], c = void 0; for (var l in u) { var v = m[l]; if (void 0 === v && (v = m[l] = new RegExp(l).test(e || "en")), v) { for (var d in c = l, u[l]) if (i(o, u[l][d])) { a = d; break; } break; } } if (!a) { t: for (var h in u) if (h !== c) { for (var p in u[h]) if (i(o, u[h][p])) { a = p; break t; } } } a || (console.debug("No font coverage for U+" + o.toString(16)), a = "latin"), A[n] = a, f[a] || S.has(a) || S.set(a, M("font-meta/" + a + ".json").then((function(t) { f[a] = t; }))), o > 65535 && (n++, r = n); }, r = 0; r < t.length; r++) n(r); return Promise.all(S.values()); })).then((function() { for (var n, r = null, e = 0; e < t.length; e++) { var a = t.codePointAt(e); if (r && (k(a) || d(r).has(a))) y[e] = y[e - 1]; else { r = f[A[e]]; var i = b[r.id]; if (!i) { var s = r.typeforms, v = g(s, o, "sans-serif"), p = g(s[v], u, "normal"), m = w(null === (n = s[v]) || void 0 === n ? void 0 : n[p], c); i = b[r.id] = l + "/font-files/" + r.id + "/" + v + "." + p + "." + m + ".woff"; } var S = h.get(i); S ?? (S = h.size, h.set(i, S)), y[e] = S; } a > 65535 && (e++, y[e] = y[e - 1]); } return { fontUrls: Array.from(h.keys()), chars: y }; })); }, Object.defineProperty(t, "__esModule", { value: !0 }), t; }({}); } /** * @typedef {string | {src:string, label?:string, unicodeRange?:string, lang?:string}} UserFont */ /** * @typedef {ClientOptions} FontResolverOptions * @property {Array|UserFont} [fonts] * @property {'normal'|'italic'} [style] * @property {'normal'|'bold'|number} [style] * @property {string} [unicodeFontsURL] */ /** * @typedef {Object} FontResolverResult * @property {Uint8Array} chars * @property {Array} fonts */ /** * @typedef {function} FontResolver * @param {string} text * @param {(FontResolverResult) => void} callback * @param {FontResolverOptions} [options] */ /** * Factory for the FontResolver function. * @param {FontParser} fontParser * @param {{getFontsForString: function, CodePointSet: function}} unicodeFontResolverClient * @return {FontResolver} */ function createFontResolver(fontParser, unicodeFontResolverClient) { /** * @type {Record} */ const parsedFonts = Object.create(null); /** * @type {Record void>>} */ const loadingFonts = Object.create(null); /** * Load a given font url */ function doLoadFont(url, callback) { const onError = (err) => { console.error(`Failure loading font ${url}`, err); }; try { const request = new XMLHttpRequest(); request.open("get", url, true); request.responseType = "arraybuffer"; request.onload = function() { if (request.status >= 400) onError(new Error(request.statusText)); else if (request.status > 0) try { const fontObj = fontParser(request.response); fontObj.src = url; callback(fontObj); } catch (e) { onError(e); } }; request.onerror = onError; request.send(); } catch (err) { onError(err); } } /** * Load a given font url if needed, invoking a callback when it's loaded. If already * loaded, the callback will be called synchronously. * @param {string} fontUrl * @param {(font: ParsedFont) => void} callback */ function loadFont(fontUrl, callback) { let font = parsedFonts[fontUrl]; if (font) callback(font); else if (loadingFonts[fontUrl]) loadingFonts[fontUrl].push(callback); else { loadingFonts[fontUrl] = [callback]; doLoadFont(fontUrl, (fontObj) => { fontObj.src = fontUrl; parsedFonts[fontUrl] = fontObj; loadingFonts[fontUrl].forEach((cb) => cb(fontObj)); delete loadingFonts[fontUrl]; }); } } /** * For a given string of text, determine which fonts are required to fully render it and * ensure those fonts are loaded. */ return function(text, callback, { lang, fonts: userFonts = [], style = "normal", weight = "normal", unicodeFontsURL } = {}) { const charResolutions = new Uint8Array(text.length); const fontResolutions = []; if (!text.length) allDone(); const fontIndices = /* @__PURE__ */ new Map(); const fallbackRanges = []; if (style !== "italic") style = "normal"; if (typeof weight !== "number") weight = weight === "bold" ? 700 : 400; if (userFonts && !Array.isArray(userFonts)) userFonts = [userFonts]; userFonts = userFonts.slice().filter((def) => !def.lang || def.lang.test(lang)).reverse(); if (userFonts.length) { const UNKNOWN = 0; const RESOLVED = 1; const NEEDS_FALLBACK = 2; let prevCharResult = UNKNOWN; (function resolveUserFonts(startIndex = 0) { for (let i = startIndex, iLen = text.length; i < iLen; i++) { const codePoint = text.codePointAt(i); if (prevCharResult === RESOLVED && fontResolutions[charResolutions[i - 1]].supportsCodePoint(codePoint) || i > 0 && /\s/.test(text[i])) { charResolutions[i] = charResolutions[i - 1]; if (prevCharResult === NEEDS_FALLBACK) fallbackRanges[fallbackRanges.length - 1][1] = i; } else for (let j = charResolutions[i], jLen = userFonts.length; j <= jLen; j++) if (j === jLen) { const range = prevCharResult === NEEDS_FALLBACK ? fallbackRanges[fallbackRanges.length - 1] : fallbackRanges[fallbackRanges.length] = [i, i]; range[1] = i; prevCharResult = NEEDS_FALLBACK; } else { charResolutions[i] = j; const { src, unicodeRange } = userFonts[j]; if (!unicodeRange || isCodeInRanges(codePoint, unicodeRange)) { const fontObj = parsedFonts[src]; if (!fontObj) { loadFont(src, () => { resolveUserFonts(i); }); return; } if (fontObj.supportsCodePoint(codePoint)) { let fontIndex = fontIndices.get(fontObj); if (typeof fontIndex !== "number") { fontIndex = fontResolutions.length; fontResolutions.push(fontObj); fontIndices.set(fontObj, fontIndex); } charResolutions[i] = fontIndex; prevCharResult = RESOLVED; break; } } } if (codePoint > 65535 && i + 1 < iLen) { charResolutions[i + 1] = charResolutions[i]; i++; if (prevCharResult === NEEDS_FALLBACK) fallbackRanges[fallbackRanges.length - 1][1] = i; } } resolveFallbacks(); })(); } else { fallbackRanges.push([0, text.length - 1]); resolveFallbacks(); } function resolveFallbacks() { if (fallbackRanges.length) { const fallbackString = fallbackRanges.map((range) => text.substring(range[0], range[1] + 1)).join("\n"); unicodeFontResolverClient.getFontsForString(fallbackString, { lang: lang || void 0, style, weight, dataUrl: unicodeFontsURL }).then(({ fontUrls, chars }) => { const fontIndexOffset = fontResolutions.length; let charIdx = 0; fallbackRanges.forEach((range) => { for (let i = 0, endIdx = range[1] - range[0]; i <= endIdx; i++) charResolutions[range[0] + i] = chars[charIdx++] + fontIndexOffset; charIdx++; }); let loadedCount = 0; fontUrls.forEach((url, i) => { loadFont(url, (fontObj) => { fontResolutions[i + fontIndexOffset] = fontObj; if (++loadedCount === fontUrls.length) allDone(); }); }); }); } else allDone(); } function allDone() { callback({ chars: charResolutions, fonts: fontResolutions }); } function isCodeInRanges(code, ranges) { for (let k = 0; k < ranges.length; k++) { const [start, end = start] = ranges[k]; if (start <= code && code <= end) return true; } return false; } }; } var fontResolverWorkerModule = /*#__PURE__*/ defineWorkerModule({ name: "FontResolver", dependencies: [ createFontResolver, workerModule, unicodeFontResolverClientFactory ], init(createFontResolver, fontParser, unicodeFontResolverClientFactory) { return createFontResolver(fontParser, unicodeFontResolverClientFactory()); } }); /** * @typedef {number|'left'|'center'|'right'} AnchorXValue */ /** * @typedef {number|'top'|'top-baseline'|'top-cap'|'top-ex'|'middle'|'bottom-baseline'|'bottom'} AnchorYValue */ /** * @typedef {object} TypesetParams * @property {string} text * @property {UserFont|UserFont[]} [font] * @property {string} [lang] * @property {number} [sdfGlyphSize=64] * @property {number} [fontSize=1] * @property {number|'normal'|'bold'} [fontWeight='normal'] * @property {'normal'|'italic'} [fontStyle='normal'] * @property {number} [letterSpacing=0] * @property {'normal'|number} [lineHeight='normal'] * @property {number} [maxWidth] * @property {'ltr'|'rtl'} [direction='ltr'] * @property {string} [textAlign='left'] * @property {number} [textIndent=0] * @property {'normal'|'nowrap'} [whiteSpace='normal'] * @property {'normal'|'break-word'} [overflowWrap='normal'] * @property {AnchorXValue} [anchorX=0] * @property {AnchorYValue} [anchorY=0] * @property {boolean} [metricsOnly=false] * @property {string} [unicodeFontsURL] * @property {FontResolverResult} [preResolvedFonts] * @property {boolean} [includeCaretPositions=false] * @property {number} [chunkedBoundsSize=8192] * @property {{[rangeStartIndex]: number}} [colorRanges] */ /** * @typedef {object} TypesetResult * @property {Uint16Array} glyphIds id for each glyph, specific to that glyph's font * @property {Uint8Array} glyphFontIndices index into fontData for each glyph * @property {Float32Array} glyphPositions x,y of each glyph's origin in layout * @property {{[font]: {[glyphId]: {path: string, pathBounds: number[]}}}} glyphData data about each glyph appearing in the text * @property {TypesetFontData[]} fontData data about each font used in the text * @property {Float32Array} [caretPositions] startX,endX,bottomY caret positions for each char * @property {Uint8Array} [glyphColors] color for each glyph, if color ranges supplied * chunkedBounds, //total rects per (n=chunkedBoundsSize) consecutive glyphs * fontSize, //calculated em height * topBaseline: anchorYOffset + lines[0].baseline, //y coordinate of the top line's baseline * blockBounds: [ //bounds for the whole block of text, including vertical padding for lineHeight * anchorXOffset, * anchorYOffset - totalHeight, * anchorXOffset + maxLineWidth, * anchorYOffset * ], * visibleBounds, //total bounds of visible text paths, may be larger or smaller than blockBounds * timings */ /** * @typedef {object} TypesetFontData * @property src * @property unitsPerEm * @property ascender * @property descender * @property lineHeight * @property capHeight * @property xHeight */ /** * @typedef {function} TypesetterTypesetFunction - compute fonts and layout for some text. * @param {TypesetParams} params * @param {(TypesetResult) => void} callback - function called when typesetting is complete. * If the params included `preResolvedFonts`, this will be called synchronously. */ /** * @typedef {function} TypesetterMeasureFunction - compute width/height for some text. * @param {TypesetParams} params * @param {(width:number, height:number) => void} callback - function called when measurement is complete. * If the params included `preResolvedFonts`, this will be called synchronously. */ /** * Factory function that creates a self-contained environment for processing text typesetting requests. * * It is important that this function has no closure dependencies, so that it can be easily injected * into the source for a Worker without requiring a build step or complex dependency loading. All its * dependencies must be passed in at initialization. * * @param {FontResolver} resolveFonts - function to resolve a string to parsed fonts * @param {object} bidi - the bidi.js implementation object * @return {{typeset: TypesetterTypesetFunction, measure: TypesetterMeasureFunction}} */ function createTypesetter(resolveFonts, bidi) { const INF = Infinity; const DEFAULT_IGNORABLE_CHARS = /[\u00AD\u034F\u061C\u115F-\u1160\u17B4-\u17B5\u180B-\u180E\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8]/; const lineBreakingWhiteSpace = `[^\\S\\u00A0]`; const BREAK_AFTER_CHARS = new RegExp(`${lineBreakingWhiteSpace}|[\\-\\u007C\\u00AD\\u2010\\u2012-\\u2014\\u2027\\u2056\\u2E17\\u2E40]`); /** * Load and parse all the necessary fonts to render a given string of text, then group * them into consecutive runs of characters sharing a font. */ function calculateFontRuns({ text, lang, fonts, style, weight, preResolvedFonts, unicodeFontsURL }, onDone) { const onResolved = ({ chars, fonts: parsedFonts }) => { let curRun, prevVal; const runs = []; for (let i = 0; i < chars.length; i++) if (chars[i] !== prevVal) { prevVal = chars[i]; runs.push(curRun = { start: i, end: i, fontObj: parsedFonts[chars[i]] }); } else curRun.end = i; onDone(runs); }; if (preResolvedFonts) onResolved(preResolvedFonts); else resolveFonts(text, onResolved, { lang, fonts, style, weight, unicodeFontsURL }); } /** * Main entry point. * Process a text string with given font and formatting parameters, and return all info * necessary to render all its glyphs. * @type TypesetterTypesetFunction */ function typeset({ text = "", font, lang, sdfGlyphSize = 64, fontSize = 400, fontWeight = 1, fontStyle = "normal", letterSpacing = 0, lineHeight = "normal", maxWidth = INF, direction, textAlign = "left", textIndent = 0, whiteSpace = "normal", overflowWrap = "normal", anchorX = 0, anchorY = 0, metricsOnly = false, unicodeFontsURL, preResolvedFonts = null, includeCaretPositions = false, chunkedBoundsSize = 8192, colorRanges = null }, callback) { const mainStart = now(); const timings = { fontLoad: 0, typesetting: 0 }; if (text.indexOf("\r") > -1) { console.info("Typesetter: got text with \\r chars; normalizing to \\n"); text = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); } fontSize = +fontSize; letterSpacing = +letterSpacing; maxWidth = +maxWidth; lineHeight = lineHeight || "normal"; textIndent = +textIndent; calculateFontRuns({ text, lang, style: fontStyle, weight: fontWeight, fonts: typeof font === "string" ? [{ src: font }] : font, unicodeFontsURL, preResolvedFonts }, (runs) => { timings.fontLoad = now() - mainStart; const hasMaxWidth = isFinite(maxWidth); let glyphIds = null; let glyphFontIndices = null; let glyphPositions = null; let glyphData = null; let glyphColors = null; let caretPositions = null; let visibleBounds = null; let chunkedBounds = null; let maxLineWidth = 0; let renderableGlyphCount = 0; let canWrap = whiteSpace !== "nowrap"; const metricsByFont = /* @__PURE__ */ new Map(); const typesetStart = now(); let lineXOffset = textIndent; let prevRunEndX = 0; let currentLine = new TextLine(); const lines = [currentLine]; runs.forEach((run) => { const { fontObj } = run; const { ascender, descender, unitsPerEm, lineGap, capHeight, xHeight } = fontObj; let fontData = metricsByFont.get(fontObj); if (!fontData) { const fontSizeMult = fontSize / unitsPerEm; const calcLineHeight = lineHeight === "normal" ? (ascender - descender + lineGap) * fontSizeMult : lineHeight * fontSize; const halfLeading = (calcLineHeight - (ascender - descender) * fontSizeMult) / 2; const caretHeight = Math.min(calcLineHeight, (ascender - descender) * fontSizeMult); const caretTop = (ascender + descender) / 2 * fontSizeMult + caretHeight / 2; fontData = { index: metricsByFont.size, src: fontObj.src, fontObj, fontSizeMult, unitsPerEm, ascender: ascender * fontSizeMult, descender: descender * fontSizeMult, capHeight: capHeight * fontSizeMult, xHeight: xHeight * fontSizeMult, lineHeight: calcLineHeight, baseline: -halfLeading - ascender * fontSizeMult, caretTop, caretBottom: caretTop - caretHeight }; metricsByFont.set(fontObj, fontData); } const { fontSizeMult } = fontData; const runText = text.slice(run.start, run.end + 1); let prevGlyphX, prevGlyphObj; fontObj.forEachGlyph(runText, fontSize, letterSpacing, (glyphObj, glyphX, glyphY, charIndex) => { glyphX += prevRunEndX; charIndex += run.start; prevGlyphX = glyphX; prevGlyphObj = glyphObj; const char = text.charAt(charIndex); const glyphWidth = glyphObj.advanceWidth * fontSizeMult; const curLineCount = currentLine.count; let nextLine; if (!("isEmpty" in glyphObj)) { glyphObj.isWhitespace = !!char && new RegExp(lineBreakingWhiteSpace).test(char); glyphObj.canBreakAfter = !!char && BREAK_AFTER_CHARS.test(char); glyphObj.isEmpty = glyphObj.xMin === glyphObj.xMax || glyphObj.yMin === glyphObj.yMax || DEFAULT_IGNORABLE_CHARS.test(char); } if (!glyphObj.isWhitespace && !glyphObj.isEmpty) renderableGlyphCount++; if (canWrap && hasMaxWidth && !glyphObj.isWhitespace && glyphX + glyphWidth + lineXOffset > maxWidth && curLineCount) { if (currentLine.glyphAt(curLineCount - 1).glyphObj.canBreakAfter) { nextLine = new TextLine(); lineXOffset = -glyphX; } else for (let i = curLineCount; i--;) if (i === 0 && overflowWrap === "break-word") { nextLine = new TextLine(); lineXOffset = -glyphX; break; } else if (currentLine.glyphAt(i).glyphObj.canBreakAfter) { nextLine = currentLine.splitAt(i + 1); const adjustX = nextLine.glyphAt(0).x; lineXOffset -= adjustX; for (let j = nextLine.count; j--;) nextLine.glyphAt(j).x -= adjustX; break; } if (nextLine) { currentLine.isSoftWrapped = true; currentLine = nextLine; lines.push(currentLine); maxLineWidth = maxWidth; } } let fly = currentLine.glyphAt(currentLine.count); fly.glyphObj = glyphObj; fly.x = glyphX + lineXOffset; fly.y = glyphY; fly.width = glyphWidth; fly.charIndex = charIndex; fly.fontData = fontData; if (char === "\n") { currentLine = new TextLine(); lines.push(currentLine); lineXOffset = -(glyphX + glyphWidth + letterSpacing * fontSize) + textIndent; } }); prevRunEndX = prevGlyphX + prevGlyphObj.advanceWidth * fontSizeMult + letterSpacing * fontSize; }); let totalHeight = 0; lines.forEach((line) => { let isTrailingWhitespace = true; for (let i = line.count; i--;) { const glyphInfo = line.glyphAt(i); if (isTrailingWhitespace && !glyphInfo.glyphObj.isWhitespace) { line.width = glyphInfo.x + glyphInfo.width; if (line.width > maxLineWidth) maxLineWidth = line.width; isTrailingWhitespace = false; } let { lineHeight, capHeight, xHeight, baseline } = glyphInfo.fontData; if (lineHeight > line.lineHeight) line.lineHeight = lineHeight; const baselineDiff = baseline - line.baseline; if (baselineDiff < 0) { line.baseline += baselineDiff; line.cap += baselineDiff; line.ex += baselineDiff; } line.cap = Math.max(line.cap, line.baseline + capHeight); line.ex = Math.max(line.ex, line.baseline + xHeight); } line.baseline -= totalHeight; line.cap -= totalHeight; line.ex -= totalHeight; totalHeight += line.lineHeight; }); let anchorXOffset = 0; let anchorYOffset = 0; if (anchorX) { if (typeof anchorX === "number") anchorXOffset = -anchorX; else if (typeof anchorX === "string") anchorXOffset = -maxLineWidth * (anchorX === "left" ? 0 : anchorX === "center" ? .5 : anchorX === "right" ? 1 : parsePercent(anchorX)); } if (anchorY) { if (typeof anchorY === "number") anchorYOffset = -anchorY; else if (typeof anchorY === "string") anchorYOffset = anchorY === "top" ? 0 : anchorY === "top-baseline" ? -lines[0].baseline : anchorY === "top-cap" ? -lines[0].cap : anchorY === "top-ex" ? -lines[0].ex : anchorY === "middle" ? totalHeight / 2 : anchorY === "bottom" ? totalHeight : anchorY === "bottom-baseline" ? -lines[lines.length - 1].baseline : parsePercent(anchorY) * totalHeight; } if (!metricsOnly) { const bidiLevelsResult = bidi.getEmbeddingLevels(text, direction); glyphIds = new Uint16Array(renderableGlyphCount); glyphFontIndices = new Uint8Array(renderableGlyphCount); glyphPositions = new Float32Array(renderableGlyphCount * 2); glyphData = {}; visibleBounds = [ INF, INF, -Infinity, -Infinity ]; chunkedBounds = []; if (includeCaretPositions) caretPositions = new Float32Array(text.length * 4); if (colorRanges) glyphColors = new Uint8Array(renderableGlyphCount * 3); let renderableGlyphIndex = 0; let prevCharIndex = -1; let colorCharIndex = -1; let chunk; let currentColor; lines.forEach((line, lineIndex) => { let { count: lineGlyphCount, width: lineWidth } = line; if (lineGlyphCount > 0) { let trailingWhitespaceCount = 0; for (let i = lineGlyphCount; i-- && line.glyphAt(i).glyphObj.isWhitespace;) trailingWhitespaceCount++; let lineXOffset = 0; let justifyAdjust = 0; if (textAlign === "center") lineXOffset = (maxLineWidth - lineWidth) / 2; else if (textAlign === "right") lineXOffset = maxLineWidth - lineWidth; else if (textAlign === "justify" && line.isSoftWrapped) { let whitespaceCount = 0; for (let i = lineGlyphCount - trailingWhitespaceCount; i--;) if (line.glyphAt(i).glyphObj.isWhitespace) whitespaceCount++; justifyAdjust = (maxLineWidth - lineWidth) / whitespaceCount; } if (justifyAdjust || lineXOffset) { let justifyOffset = 0; for (let i = 0; i < lineGlyphCount; i++) { let glyphInfo = line.glyphAt(i); const glyphObj = glyphInfo.glyphObj; glyphInfo.x += lineXOffset + justifyOffset; if (justifyAdjust !== 0 && glyphObj.isWhitespace && i < lineGlyphCount - trailingWhitespaceCount) { justifyOffset += justifyAdjust; glyphInfo.width += justifyAdjust; } } } const flips = bidi.getReorderSegments(text, bidiLevelsResult, line.glyphAt(0).charIndex, line.glyphAt(line.count - 1).charIndex); for (let fi = 0; fi < flips.length; fi++) { const [start, end] = flips[fi]; let left = Infinity, right = -Infinity; for (let i = 0; i < lineGlyphCount; i++) if (line.glyphAt(i).charIndex >= start) { let startInLine = i, endInLine = i; for (; endInLine < lineGlyphCount; endInLine++) { let info = line.glyphAt(endInLine); if (info.charIndex > end) break; if (endInLine < lineGlyphCount - trailingWhitespaceCount) { left = Math.min(left, info.x); right = Math.max(right, info.x + info.width); } } for (let j = startInLine; j < endInLine; j++) { const glyphInfo = line.glyphAt(j); glyphInfo.x = right - (glyphInfo.x + glyphInfo.width - left); } break; } } let glyphObj; const setGlyphObj = (g) => glyphObj = g; for (let i = 0; i < lineGlyphCount; i++) { const glyphInfo = line.glyphAt(i); glyphObj = glyphInfo.glyphObj; const glyphId = glyphObj.index; const rtl = bidiLevelsResult.levels[glyphInfo.charIndex] & 1; if (rtl) { const mirrored = bidi.getMirroredCharacter(text[glyphInfo.charIndex]); if (mirrored) glyphInfo.fontData.fontObj.forEachGlyph(mirrored, 0, 0, setGlyphObj); } if (includeCaretPositions) { const { charIndex, fontData } = glyphInfo; const caretLeft = glyphInfo.x + anchorXOffset; const caretRight = glyphInfo.x + glyphInfo.width + anchorXOffset; caretPositions[charIndex * 4] = rtl ? caretRight : caretLeft; caretPositions[charIndex * 4 + 1] = rtl ? caretLeft : caretRight; caretPositions[charIndex * 4 + 2] = line.baseline + fontData.caretBottom + anchorYOffset; caretPositions[charIndex * 4 + 3] = line.baseline + fontData.caretTop + anchorYOffset; const ligCount = charIndex - prevCharIndex; if (ligCount > 1) fillLigatureCaretPositions(caretPositions, prevCharIndex, ligCount); prevCharIndex = charIndex; } if (colorRanges) { const { charIndex } = glyphInfo; while (charIndex > colorCharIndex) { colorCharIndex++; if (colorRanges.hasOwnProperty(colorCharIndex)) currentColor = colorRanges[colorCharIndex]; } } if (!glyphObj.isWhitespace && !glyphObj.isEmpty) { const idx = renderableGlyphIndex++; const { fontSizeMult, src: fontSrc, index: fontIndex } = glyphInfo.fontData; const fontGlyphData = glyphData[fontSrc] || (glyphData[fontSrc] = {}); if (!fontGlyphData[glyphId]) fontGlyphData[glyphId] = { path: glyphObj.path, pathBounds: [ glyphObj.xMin, glyphObj.yMin, glyphObj.xMax, glyphObj.yMax ] }; const glyphX = glyphInfo.x + anchorXOffset; const glyphY = glyphInfo.y + line.baseline + anchorYOffset; glyphPositions[idx * 2] = glyphX; glyphPositions[idx * 2 + 1] = glyphY; const visX0 = glyphX + glyphObj.xMin * fontSizeMult; const visY0 = glyphY + glyphObj.yMin * fontSizeMult; const visX1 = glyphX + glyphObj.xMax * fontSizeMult; const visY1 = glyphY + glyphObj.yMax * fontSizeMult; if (visX0 < visibleBounds[0]) visibleBounds[0] = visX0; if (visY0 < visibleBounds[1]) visibleBounds[1] = visY0; if (visX1 > visibleBounds[2]) visibleBounds[2] = visX1; if (visY1 > visibleBounds[3]) visibleBounds[3] = visY1; if (idx % chunkedBoundsSize === 0) { chunk = { start: idx, end: idx, rect: [ INF, INF, -Infinity, -Infinity ] }; chunkedBounds.push(chunk); } chunk.end++; const chunkRect = chunk.rect; if (visX0 < chunkRect[0]) chunkRect[0] = visX0; if (visY0 < chunkRect[1]) chunkRect[1] = visY0; if (visX1 > chunkRect[2]) chunkRect[2] = visX1; if (visY1 > chunkRect[3]) chunkRect[3] = visY1; glyphIds[idx] = glyphId; glyphFontIndices[idx] = fontIndex; if (colorRanges) { const start = idx * 3; glyphColors[start] = currentColor >> 16 & 255; glyphColors[start + 1] = currentColor >> 8 & 255; glyphColors[start + 2] = currentColor & 255; } } } } }); if (caretPositions) { const ligCount = text.length - prevCharIndex; if (ligCount > 1) fillLigatureCaretPositions(caretPositions, prevCharIndex, ligCount); } } const fontData = []; metricsByFont.forEach(({ index, src, unitsPerEm, ascender, descender, lineHeight, capHeight, xHeight }) => { fontData[index] = { src, unitsPerEm, ascender, descender, lineHeight, capHeight, xHeight }; }); timings.typesetting = now() - typesetStart; callback({ glyphIds, glyphFontIndices, glyphPositions, glyphData, fontData, caretPositions, glyphColors, chunkedBounds, fontSize, topBaseline: anchorYOffset + lines[0].baseline, blockBounds: [ anchorXOffset, anchorYOffset - totalHeight, anchorXOffset + maxLineWidth, anchorYOffset ], visibleBounds, timings }); }); } /** * For a given text string and font parameters, determine the resulting block dimensions * after wrapping for the given maxWidth. * @param args * @param callback */ function measure(args, callback) { typeset({ ...args, metricsOnly: true }, (result) => { const [x0, y0, x1, y1] = result.blockBounds; callback({ width: x1 - x0, height: y1 - y0 }); }); } function parsePercent(str) { let match = str.match(/^([\d.]+)%$/); let pct = match ? parseFloat(match[1]) : NaN; return isNaN(pct) ? 0 : pct / 100; } function fillLigatureCaretPositions(caretPositions, ligStartIndex, ligCount) { const ligStartX = caretPositions[ligStartIndex * 4]; const ligEndX = caretPositions[ligStartIndex * 4 + 1]; const ligBottom = caretPositions[ligStartIndex * 4 + 2]; const ligTop = caretPositions[ligStartIndex * 4 + 3]; const guessedAdvanceX = (ligEndX - ligStartX) / ligCount; for (let i = 0; i < ligCount; i++) { const startIndex = (ligStartIndex + i) * 4; caretPositions[startIndex] = ligStartX + guessedAdvanceX * i; caretPositions[startIndex + 1] = ligStartX + guessedAdvanceX * (i + 1); caretPositions[startIndex + 2] = ligBottom; caretPositions[startIndex + 3] = ligTop; } } function now() { return (self.performance || Date).now(); } function TextLine() { this.data = []; } const textLineProps = [ "glyphObj", "x", "y", "width", "charIndex", "fontData" ]; TextLine.prototype = { width: 0, lineHeight: 0, baseline: 0, cap: 0, ex: 0, isSoftWrapped: false, get count() { return Math.ceil(this.data.length / textLineProps.length); }, glyphAt(i) { let fly = TextLine.flyweight; fly.data = this.data; fly.index = i; return fly; }, splitAt(i) { let newLine = new TextLine(); newLine.data = this.data.splice(i * textLineProps.length); return newLine; } }; TextLine.flyweight = textLineProps.reduce((obj, prop, i, all) => { Object.defineProperty(obj, prop, { get() { return this.data[this.index * textLineProps.length + i]; }, set(val) { this.data[this.index * textLineProps.length + i] = val; } }); return obj; }, { data: null, index: 0 }); return { typeset, measure }; } var now$1 = () => (self.performance || Date).now(); var mainThreadGenerator = /*#__PURE__*/ SDFGenerator(); var warned; /** * Generate an SDF texture image for a single glyph path, placing the result into a webgl canvas at a * given location and channel. Utilizes the webgl-sdf-generator external package for GPU-accelerated SDF * generation when supported. */ function generateSDF(width, height, path, viewBox, distance, exponent, canvas, x, y, channel, useWebGL = true) { if (!useWebGL) return generateSDF_JS_Worker(width, height, path, viewBox, distance, exponent, canvas, x, y, channel); return generateSDF_GL(width, height, path, viewBox, distance, exponent, canvas, x, y, channel).then(null, (err) => { if (!warned) { console.warn(`WebGL SDF generation failed, falling back to JS`, err); warned = true; } return generateSDF_JS_Worker(width, height, path, viewBox, distance, exponent, canvas, x, y, channel); }); } var queue = []; var chunkTimeBudget = 5; var timer = 0; function nextChunk() { const start = now$1(); while (queue.length && now$1() - start < chunkTimeBudget) queue.shift()(); timer = queue.length ? setTimeout(nextChunk, 0) : 0; } /** * WebGL-based implementation executed on the main thread. Requests are executed in time-bounded * macrotask chunks to allow render frames to execute in between. */ var generateSDF_GL = (...args) => { return new Promise((resolve, reject) => { queue.push(() => { const start = now$1(); try { mainThreadGenerator.webgl.generateIntoCanvas(...args); resolve({ timing: now$1() - start }); } catch (err) { reject(err); } }); if (!timer) timer = setTimeout(nextChunk, 0); }); }; var threadCount = 4; var idleTimeout = 2e3; var threads = {}; var callNum = 0; /** * Fallback JS-based implementation, fanned out to a number of worker threads for parallelism */ function generateSDF_JS_Worker(width, height, path, viewBox, distance, exponent, canvas, x, y, channel) { const workerId = "TroikaTextSDFGenerator_JS_" + callNum++ % threadCount; let thread = threads[workerId]; if (!thread) thread = threads[workerId] = { workerModule: defineWorkerModule({ name: workerId, workerId, dependencies: [SDFGenerator, now$1], init(_createSDFGenerator, now) { const generate = _createSDFGenerator().javascript.generate; return function(...args) { const start = now(); return { textureData: generate(...args), timing: now() - start }; }; }, getTransferables(result) { return [result.textureData.buffer]; } }), requests: 0, idleTimer: null }; thread.requests++; clearTimeout(thread.idleTimer); return thread.workerModule(width, height, path, viewBox, distance, exponent).then(({ textureData, timing }) => { const start = now$1(); const imageData = new Uint8Array(textureData.length * 4); for (let i = 0; i < textureData.length; i++) imageData[i * 4 + channel] = textureData[i]; mainThreadGenerator.webglUtils.renderImageData(canvas, imageData, x, y, width, height, 1 << 3 - channel); timing += now$1() - start; if (--thread.requests === 0) thread.idleTimer = setTimeout(() => { terminateWorker(workerId); }, idleTimeout); return { timing }; }); } function warmUpSDFCanvas(canvas) { if (!canvas._warm) { mainThreadGenerator.webgl.isSupported(canvas); canvas._warm = true; } } var resizeWebGLCanvasWithoutClearing = mainThreadGenerator.webglUtils.resizeWebGLCanvasWithoutClearing; var CONFIG = { defaultFontURL: null, unicodeFontsURL: null, sdfGlyphSize: 64, sdfMargin: 1 / 16, sdfExponent: 9, textureWidth: 2048, useWorker: true }; var tempColor = /*#__PURE__*/ new Color(); function now$1$1() { return (self.performance || Date).now(); } /** * Repository for all font SDF atlas textures and their glyph mappings. There is a separate atlas for * each sdfGlyphSize. Each atlas has a single Texture that holds all glyphs for all fonts. * * { * [sdfGlyphSize]: { * glyphCount: number, * sdfGlyphSize: number, * sdfTexture: Texture, * sdfCanvas: HTMLCanvasElement, * contextLost: boolean, * glyphsByFont: Map> * } * } */ var atlases = Object.create(null); /** * @typedef {object} TroikaTextRenderInfo - Format of the result from `getTextRenderInfo`. * @property {TypesetParams} parameters - The normalized input arguments to the render call. * @property {Texture} sdfTexture - The SDF atlas texture. * @property {number} sdfGlyphSize - The size of each glyph's SDF; see `configureTextBuilder`. * @property {number} sdfExponent - The exponent used in encoding the SDF's values; see `configureTextBuilder`. * @property {Float32Array} glyphBounds - List of [minX, minY, maxX, maxY] quad bounds for each glyph. * @property {Float32Array} glyphAtlasIndices - List holding each glyph's index in the SDF atlas. * @property {Uint8Array} [glyphColors] - List holding each glyph's [r, g, b] color, if `colorRanges` was supplied. * @property {Float32Array} [caretPositions] - A list of caret positions for all characters in the string; each is * four elements: the starting X, the ending X, the bottom Y, and the top Y for the caret. * @property {number} [caretHeight] - An appropriate height for all selection carets. * @property {number} ascender - The font's ascender metric. * @property {number} descender - The font's descender metric. * @property {number} capHeight - The font's cap height metric, based on the height of Latin capital letters. * @property {number} xHeight - The font's x height metric, based on the height of Latin lowercase letters. * @property {number} lineHeight - The final computed lineHeight measurement. * @property {number} topBaseline - The y position of the top line's baseline. * @property {Array} blockBounds - The total [minX, minY, maxX, maxY] rect of the whole text block; * this can include extra vertical space beyond the visible glyphs due to lineHeight, and is * equivalent to the dimensions of a block-level text element in CSS. * @property {Array} visibleBounds - The total [minX, minY, maxX, maxY] rect of the whole text block; * unlike `blockBounds` this is tightly wrapped to the visible glyph paths. * @property {Array} chunkedBounds - List of bounding rects for each consecutive set of N glyphs, * in the format `{start:N, end:N, rect:[minX, minY, maxX, maxY]}`. * @property {object} timings - Timing info for various parts of the rendering logic including SDF * generation, typesetting, etc. * @frozen */ /** * @callback getTextRenderInfo~callback * @param {TroikaTextRenderInfo} textRenderInfo */ /** * Main entry point for requesting the data needed to render a text string with given font parameters. * This is an asynchronous call, performing most of the logic in a web worker thread. * @param {TypesetParams} args * @param {getTextRenderInfo~callback} callback */ function getTextRenderInfo(args, callback) { args = assign({}, args); const totalStart = now$1$1(); const { defaultFontURL } = CONFIG; const fonts = []; if (defaultFontURL) fonts.push({ label: "default", src: toAbsoluteURL(defaultFontURL) }); if (args.font) fonts.push({ label: "user", src: toAbsoluteURL(args.font) }); args.font = fonts; args.text = "" + args.text; args.sdfGlyphSize = args.sdfGlyphSize || CONFIG.sdfGlyphSize; args.unicodeFontsURL = args.unicodeFontsURL || CONFIG.unicodeFontsURL; if (args.colorRanges != null) { let colors = {}; for (let key in args.colorRanges) if (args.colorRanges.hasOwnProperty(key)) { let val = args.colorRanges[key]; if (typeof val !== "number") val = tempColor.set(val).getHex(); colors[key] = val; } args.colorRanges = colors; } Object.freeze(args); const { textureWidth, sdfExponent } = CONFIG; const { sdfGlyphSize } = args; const glyphsPerRow = textureWidth / sdfGlyphSize * 4; let atlas = atlases[sdfGlyphSize]; if (!atlas) { const canvas = document.createElement("canvas"); canvas.width = textureWidth; canvas.height = sdfGlyphSize * 256 / glyphsPerRow; atlas = atlases[sdfGlyphSize] = { glyphCount: 0, sdfGlyphSize, sdfCanvas: canvas, sdfTexture: new Texture$1(canvas, void 0, void 0, void 0, LinearFilter, LinearFilter), contextLost: false, glyphsByFont: /* @__PURE__ */ new Map() }; atlas.sdfTexture.generateMipmaps = false; initContextLossHandling(atlas); } const { sdfTexture, sdfCanvas } = atlas; (CONFIG.useWorker ? typesetInWorker : typesetOnMainThread)(args).then((result) => { const { glyphIds, glyphFontIndices, fontData, glyphPositions, fontSize, timings } = result; const neededSDFs = []; const glyphBounds = new Float32Array(glyphIds.length * 4); let boundsIdx = 0; let positionsIdx = 0; const quadsStart = now$1$1(); const fontGlyphMaps = fontData.map((font) => { let map = atlas.glyphsByFont.get(font.src); if (!map) atlas.glyphsByFont.set(font.src, map = /* @__PURE__ */ new Map()); return map; }); glyphIds.forEach((glyphId, i) => { const fontIndex = glyphFontIndices[i]; const { src: fontSrc, unitsPerEm } = fontData[fontIndex]; let glyphInfo = fontGlyphMaps[fontIndex].get(glyphId); if (!glyphInfo) { const { path, pathBounds } = result.glyphData[fontSrc][glyphId]; const fontUnitsMargin = Math.max(pathBounds[2] - pathBounds[0], pathBounds[3] - pathBounds[1]) / sdfGlyphSize * (CONFIG.sdfMargin * sdfGlyphSize + .5); const atlasIndex = atlas.glyphCount++; const sdfViewBox = [ pathBounds[0] - fontUnitsMargin, pathBounds[1] - fontUnitsMargin, pathBounds[2] + fontUnitsMargin, pathBounds[3] + fontUnitsMargin ]; fontGlyphMaps[fontIndex].set(glyphId, glyphInfo = { path, atlasIndex, sdfViewBox }); neededSDFs.push(glyphInfo); } const { sdfViewBox } = glyphInfo; const posX = glyphPositions[positionsIdx++]; const posY = glyphPositions[positionsIdx++]; const fontSizeMult = fontSize / unitsPerEm; glyphBounds[boundsIdx++] = posX + sdfViewBox[0] * fontSizeMult; glyphBounds[boundsIdx++] = posY + sdfViewBox[1] * fontSizeMult; glyphBounds[boundsIdx++] = posX + sdfViewBox[2] * fontSizeMult; glyphBounds[boundsIdx++] = posY + sdfViewBox[3] * fontSizeMult; glyphIds[i] = glyphInfo.atlasIndex; }); timings.quads = (timings.quads || 0) + (now$1$1() - quadsStart); const sdfStart = now$1$1(); timings.sdf = {}; const currentHeight = sdfCanvas.height; const neededRows = Math.ceil(atlas.glyphCount / glyphsPerRow); const neededHeight = Math.pow(2, Math.ceil(Math.log2(neededRows * sdfGlyphSize))); if (neededHeight > currentHeight) { console.info(`Increasing SDF texture size ${currentHeight}->${neededHeight}`); resizeWebGLCanvasWithoutClearing(sdfCanvas, textureWidth, neededHeight); sdfTexture.dispose(); } Promise.all(neededSDFs.map((glyphInfo) => generateGlyphSDF(glyphInfo, atlas, args.gpuAccelerateSDF).then(({ timing }) => { timings.sdf[glyphInfo.atlasIndex] = timing; }))).then(() => { if (neededSDFs.length && !atlas.contextLost) { safariPre15Workaround(atlas); sdfTexture.needsUpdate = true; } timings.sdfTotal = now$1$1() - sdfStart; timings.total = now$1$1() - totalStart; callback(Object.freeze({ parameters: args, sdfTexture, sdfGlyphSize, sdfExponent, glyphBounds, glyphAtlasIndices: glyphIds, glyphColors: result.glyphColors, caretPositions: result.caretPositions, chunkedBounds: result.chunkedBounds, ascender: result.ascender, descender: result.descender, lineHeight: result.lineHeight, capHeight: result.capHeight, xHeight: result.xHeight, topBaseline: result.topBaseline, blockBounds: result.blockBounds, visibleBounds: result.visibleBounds, timings: result.timings })); }); }); Promise.resolve().then(() => { if (!atlas.contextLost) warmUpSDFCanvas(sdfCanvas); }); } function generateGlyphSDF({ path, atlasIndex, sdfViewBox }, { sdfGlyphSize, sdfCanvas, contextLost }, useGPU) { if (contextLost) return Promise.resolve({ timing: -1 }); const { textureWidth, sdfExponent } = CONFIG; const maxDist = Math.max(sdfViewBox[2] - sdfViewBox[0], sdfViewBox[3] - sdfViewBox[1]); const squareIndex = Math.floor(atlasIndex / 4); return generateSDF(sdfGlyphSize, sdfGlyphSize, path, sdfViewBox, maxDist, sdfExponent, sdfCanvas, squareIndex % (textureWidth / sdfGlyphSize) * sdfGlyphSize, Math.floor(squareIndex / (textureWidth / sdfGlyphSize)) * sdfGlyphSize, atlasIndex % 4, useGPU); } function initContextLossHandling(atlas) { const canvas = atlas.sdfCanvas; canvas.addEventListener("webglcontextlost", (event) => { console.log("Context Lost", event); event.preventDefault(); atlas.contextLost = true; }); canvas.addEventListener("webglcontextrestored", (event) => { console.log("Context Restored", event); atlas.contextLost = false; const promises = []; atlas.glyphsByFont.forEach((glyphMap) => { glyphMap.forEach((glyph) => { promises.push(generateGlyphSDF(glyph, atlas, true)); }); }); Promise.all(promises).then(() => { safariPre15Workaround(atlas); atlas.sdfTexture.needsUpdate = true; }); }); } /** * Preload a given font and optionally pre-generate glyph SDFs for one or more character sequences. * This can be useful to avoid long pauses when first showing text in a scene, by preloading the * needed fonts and glyphs up front along with other assets. * * @param {object} options * @param {string} options.font - URL of the font file to preload. If not given, the default font will * be loaded. * @param {string|string[]} options.characters - One or more character sequences for which to pre- * generate glyph SDFs. Note that this will honor ligature substitution, so you may need * to specify ligature sequences in addition to their individual characters to get all * possible glyphs, e.g. `["t", "h", "th"]` to get the "t" and "h" glyphs plus the "th" ligature. * @param {number} options.sdfGlyphSize - The size at which to prerender the SDF textures for the * specified `characters`. * @param {function} callback - A function that will be called when the preloading is complete. */ function preloadFont({ font, characters, sdfGlyphSize }, callback) { getTextRenderInfo({ font, sdfGlyphSize, text: Array.isArray(characters) ? characters.join("\n") : "" + characters }, callback); } function assign(toObj, fromObj) { for (let key in fromObj) if (fromObj.hasOwnProperty(key)) toObj[key] = fromObj[key]; return toObj; } var linkEl; function toAbsoluteURL(path) { if (!linkEl) linkEl = typeof document === "undefined" ? {} : document.createElement("a"); linkEl.href = path; return linkEl.href; } /** * Safari < v15 seems unable to use the SDF webgl canvas as a texture. This applies a workaround * where it reads the pixels out of that canvas and uploads them as a data texture instead, at * a slight performance cost. */ function safariPre15Workaround(atlas) { if (typeof createImageBitmap !== "function") { console.info("Safari<15: applying SDF canvas workaround"); const { sdfCanvas, sdfTexture } = atlas; const { width, height } = sdfCanvas; const gl = atlas.sdfCanvas.getContext("webgl"); let pixels = sdfTexture.image.data; if (!pixels || pixels.length !== width * height * 4) { pixels = new Uint8Array(width * height * 4); sdfTexture.image = { width, height, data: pixels }; sdfTexture.flipY = false; sdfTexture.isDataTexture = true; } gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); } } var typesetInWorker = /*#__PURE__*/ defineWorkerModule({ name: "Typesetter", dependencies: [/* @__PURE__ */ defineWorkerModule({ name: "Typesetter", dependencies: [ createTypesetter, fontResolverWorkerModule, bidiFactory ], init(createTypesetter, fontResolver, bidiFactory) { return createTypesetter(fontResolver, bidiFactory()); } })], init(typesetter) { return function(args) { return new Promise((resolve) => { typesetter.typeset(args, resolve); }); }; }, getTransferables(result) { const transferables = []; for (let p in result) if (result[p] && result[p].buffer) transferables.push(result[p].buffer); return transferables; } }); var typesetOnMainThread = typesetInWorker.onMainThread; var templateGeometries = {}; function getTemplateGeometry(detail) { let geom = templateGeometries[detail]; if (!geom) geom = templateGeometries[detail] = new PlaneGeometry(1, 1, detail, detail).translate(.5, .5, 0); return geom; } var glyphBoundsAttrName = "aTroikaGlyphBounds"; var glyphIndexAttrName = "aTroikaGlyphIndex"; var glyphColorAttrName = "aTroikaGlyphColor"; /** @class GlyphsGeometry A specialized Geometry for rendering a set of text glyphs. Uses InstancedBufferGeometry to render the glyphs using GPU instancing of a single quad, rather than constructing a whole geometry with vertices, for much smaller attribute arraybuffers according to this math: Where N = number of glyphs... Instanced: - position: 4 * 3 - index: 2 * 3 - normal: 4 * 3 - uv: 4 * 2 - glyph x/y bounds: N * 4 - glyph indices: N * 1 = 5N + 38 Non-instanced: - position: N * 4 * 3 - index: N * 2 * 3 - normal: N * 4 * 3 - uv: N * 4 * 2 - glyph indices: N * 1 = 39N A downside of this is the rare-but-possible lack of the instanced arrays extension, which we could potentially work around with a fallback non-instanced implementation. */ var GlyphsGeometry = class extends InstancedBufferGeometry { constructor() { super(); this.detail = 1; this.curveRadius = 0; this.groups = [{ start: 0, count: Infinity, materialIndex: 0 }, { start: 0, count: Infinity, materialIndex: 1 }]; this.boundingSphere = new Sphere$1(); this.boundingBox = new Box3(); } computeBoundingSphere() {} computeBoundingBox() {} set detail(detail) { if (detail !== this._detail) { this._detail = detail; if (typeof detail !== "number" || detail < 1) detail = 1; let tpl = getTemplateGeometry(detail); [ "position", "normal", "uv" ].forEach((attr) => { this.attributes[attr] = tpl.attributes[attr].clone(); }); this.setIndex(tpl.getIndex().clone()); } } get detail() { return this._detail; } set curveRadius(r) { if (r !== this._curveRadius) { this._curveRadius = r; this._updateBounds(); } } get curveRadius() { return this._curveRadius; } /** * Update the geometry for a new set of glyphs. * @param {Float32Array} glyphBounds - An array holding the planar bounds for all glyphs * to be rendered, 4 entries for each glyph: x1,x2,y1,y1 * @param {Float32Array} glyphAtlasIndices - An array holding the index of each glyph within * the SDF atlas texture. * @param {Array} blockBounds - An array holding the [minX, minY, maxX, maxY] across all glyphs * @param {Array} [chunkedBounds] - An array of objects describing bounds for each chunk of N * consecutive glyphs: `{start:N, end:N, rect:[minX, minY, maxX, maxY]}`. This can be * used with `applyClipRect` to choose an optimized `instanceCount`. * @param {Uint8Array} [glyphColors] - An array holding r,g,b values for each glyph. */ updateGlyphs(glyphBounds, glyphAtlasIndices, blockBounds, chunkedBounds, glyphColors) { this.updateAttributeData(glyphBoundsAttrName, glyphBounds, 4); this.updateAttributeData(glyphIndexAttrName, glyphAtlasIndices, 1); this.updateAttributeData(glyphColorAttrName, glyphColors, 3); this._blockBounds = blockBounds; this._chunkedBounds = chunkedBounds; this.instanceCount = glyphAtlasIndices.length; this._updateBounds(); } _updateBounds() { const bounds = this._blockBounds; if (bounds) { const { curveRadius, boundingBox: bbox } = this; if (curveRadius) { const { PI, floor, min, max, sin, cos } = Math; const halfPi = PI / 2; const twoPi = PI * 2; const absR = Math.abs(curveRadius); const leftAngle = bounds[0] / absR; const rightAngle = bounds[2] / absR; const minX = floor((leftAngle + halfPi) / twoPi) !== floor((rightAngle + halfPi) / twoPi) ? -absR : min(sin(leftAngle) * absR, sin(rightAngle) * absR); const maxX = floor((leftAngle - halfPi) / twoPi) !== floor((rightAngle - halfPi) / twoPi) ? absR : max(sin(leftAngle) * absR, sin(rightAngle) * absR); const maxZ = floor((leftAngle + PI) / twoPi) !== floor((rightAngle + PI) / twoPi) ? absR * 2 : max(absR - cos(leftAngle) * absR, absR - cos(rightAngle) * absR); bbox.min.set(minX, bounds[1], curveRadius < 0 ? -maxZ : 0); bbox.max.set(maxX, bounds[3], curveRadius < 0 ? 0 : maxZ); } else { bbox.min.set(bounds[0], bounds[1], 0); bbox.max.set(bounds[2], bounds[3], 0); } bbox.getBoundingSphere(this.boundingSphere); } } /** * Given a clipping rect, and the chunkedBounds from the last updateGlyphs call, choose the lowest * `instanceCount` that will show all glyphs within the clipped view. This is an optimization * for long blocks of text that are clipped, to skip vertex shader evaluation for glyphs that would * be clipped anyway. * * Note that since `drawElementsInstanced[ANGLE]` only accepts an instance count and not a starting * offset, this optimization becomes less effective as the clipRect moves closer to the end of the * text block. We could fix that by switching from instancing to a full geometry with a drawRange, * but at the expense of much larger attribute buffers (see classdoc above.) * * @param {Vector4} clipRect */ applyClipRect(clipRect) { let count = this.getAttribute(glyphIndexAttrName).count; let chunks = this._chunkedBounds; if (chunks) for (let i = chunks.length; i--;) { count = chunks[i].end; let rect = chunks[i].rect; if (rect[1] < clipRect.w && rect[3] > clipRect.y && rect[0] < clipRect.z && rect[2] > clipRect.x) break; } this.instanceCount = count; } /** * Utility for updating instance attributes with automatic resizing */ updateAttributeData(attrName, newArray, itemSize) { const attr = this.getAttribute(attrName); if (newArray) if (attr && attr.array.length === newArray.length) { attr.array.set(newArray); attr.needsUpdate = true; } else { this.setAttribute(attrName, new InstancedBufferAttribute(newArray, itemSize)); delete this._maxInstanceCount; this.dispose(); } else if (attr) this.deleteAttribute(attrName); } }; var VERTEX_DEFS = ` uniform vec2 uTroikaSDFTextureSize; uniform float uTroikaSDFGlyphSize; uniform vec4 uTroikaTotalBounds; uniform vec4 uTroikaClipRect; uniform mat3 uTroikaOrient; uniform bool uTroikaUseGlyphColors; uniform float uTroikaEdgeOffset; uniform float uTroikaBlurRadius; uniform vec2 uTroikaPositionOffset; uniform float uTroikaCurveRadius; attribute vec4 aTroikaGlyphBounds; attribute float aTroikaGlyphIndex; attribute vec3 aTroikaGlyphColor; varying vec2 vTroikaGlyphUV; varying vec4 vTroikaTextureUVBounds; varying float vTroikaTextureChannel; varying vec3 vTroikaGlyphColor; varying vec2 vTroikaGlyphDimensions; `; var VERTEX_TRANSFORM = ` vec4 bounds = aTroikaGlyphBounds; bounds.xz += uTroikaPositionOffset.x; bounds.yw -= uTroikaPositionOffset.y; vec4 outlineBounds = vec4( bounds.xy - uTroikaEdgeOffset - uTroikaBlurRadius, bounds.zw + uTroikaEdgeOffset + uTroikaBlurRadius ); vec4 clippedBounds = vec4( clamp(outlineBounds.xy, uTroikaClipRect.xy, uTroikaClipRect.zw), clamp(outlineBounds.zw, uTroikaClipRect.xy, uTroikaClipRect.zw) ); vec2 clippedXY = (mix(clippedBounds.xy, clippedBounds.zw, position.xy) - bounds.xy) / (bounds.zw - bounds.xy); position.xy = mix(bounds.xy, bounds.zw, clippedXY); uv = (position.xy - uTroikaTotalBounds.xy) / (uTroikaTotalBounds.zw - uTroikaTotalBounds.xy); float rad = uTroikaCurveRadius; if (rad != 0.0) { float angle = position.x / rad; position.xz = vec2(sin(angle) * rad, rad - cos(angle) * rad); normal.xz = vec2(sin(angle), cos(angle)); } position = uTroikaOrient * position; normal = uTroikaOrient * normal; vTroikaGlyphUV = clippedXY.xy; vTroikaGlyphDimensions = vec2(bounds[2] - bounds[0], bounds[3] - bounds[1]); float txCols = uTroikaSDFTextureSize.x / uTroikaSDFGlyphSize; vec2 txUvPerSquare = uTroikaSDFGlyphSize / uTroikaSDFTextureSize; vec2 txStartUV = txUvPerSquare * vec2( mod(floor(aTroikaGlyphIndex / 4.0), txCols), floor(floor(aTroikaGlyphIndex / 4.0) / txCols) ); vTroikaTextureUVBounds = vec4(txStartUV, vec2(txStartUV) + txUvPerSquare); vTroikaTextureChannel = mod(aTroikaGlyphIndex, 4.0); `; var FRAGMENT_DEFS = ` uniform sampler2D uTroikaSDFTexture; uniform vec2 uTroikaSDFTextureSize; uniform float uTroikaSDFGlyphSize; uniform float uTroikaSDFExponent; uniform float uTroikaEdgeOffset; uniform float uTroikaFillOpacity; uniform float uTroikaBlurRadius; uniform vec3 uTroikaStrokeColor; uniform float uTroikaStrokeWidth; uniform float uTroikaStrokeOpacity; uniform bool uTroikaSDFDebug; varying vec2 vTroikaGlyphUV; varying vec4 vTroikaTextureUVBounds; varying float vTroikaTextureChannel; varying vec2 vTroikaGlyphDimensions; float troikaSdfValueToSignedDistance(float alpha) { // Inverse of exponential encoding in webgl-sdf-generator float maxDimension = max(vTroikaGlyphDimensions.x, vTroikaGlyphDimensions.y); float absDist = (1.0 - pow(2.0 * (alpha > 0.5 ? 1.0 - alpha : alpha), 1.0 / uTroikaSDFExponent)) * maxDimension; float signedDist = absDist * (alpha > 0.5 ? -1.0 : 1.0); return signedDist; } float troikaGlyphUvToSdfValue(vec2 glyphUV) { vec2 textureUV = mix(vTroikaTextureUVBounds.xy, vTroikaTextureUVBounds.zw, glyphUV); vec4 rgba = texture2D(uTroikaSDFTexture, textureUV); float ch = floor(vTroikaTextureChannel + 0.5); //NOTE: can't use round() in WebGL1 return ch == 0.0 ? rgba.r : ch == 1.0 ? rgba.g : ch == 2.0 ? rgba.b : rgba.a; } float troikaGlyphUvToDistance(vec2 uv) { return troikaSdfValueToSignedDistance(troikaGlyphUvToSdfValue(uv)); } float troikaGetAADist() { #if defined(GL_OES_standard_derivatives) || __VERSION__ >= 300 return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.5; #else return vTroikaGlyphDimensions.x / 64.0; #endif } float troikaGetFragDistValue() { vec2 clampedGlyphUV = clamp(vTroikaGlyphUV, 0.5 / uTroikaSDFGlyphSize, 1.0 - 0.5 / uTroikaSDFGlyphSize); float distance = troikaGlyphUvToDistance(clampedGlyphUV); // Extrapolate distance when outside bounds: distance += clampedGlyphUV == vTroikaGlyphUV ? 0.0 : length((vTroikaGlyphUV - clampedGlyphUV) * vTroikaGlyphDimensions); return distance; } float troikaGetEdgeAlpha(float distance, float distanceOffset, float aaDist) { #if defined(IS_DEPTH_MATERIAL) || defined(IS_DISTANCE_MATERIAL) float alpha = step(-distanceOffset, -distance); #else float alpha = smoothstep( distanceOffset + aaDist, distanceOffset - aaDist, distance ); #endif return alpha; } `; var FRAGMENT_TRANSFORM = ` float aaDist = troikaGetAADist(); float fragDistance = troikaGetFragDistValue(); float edgeAlpha = uTroikaSDFDebug ? troikaGlyphUvToSdfValue(vTroikaGlyphUV) : troikaGetEdgeAlpha(fragDistance, uTroikaEdgeOffset, max(aaDist, uTroikaBlurRadius)); #if !defined(IS_DEPTH_MATERIAL) && !defined(IS_DISTANCE_MATERIAL) vec4 fillRGBA = gl_FragColor; fillRGBA.a *= uTroikaFillOpacity; vec4 strokeRGBA = uTroikaStrokeWidth == 0.0 ? fillRGBA : vec4(uTroikaStrokeColor, uTroikaStrokeOpacity); if (fillRGBA.a == 0.0) fillRGBA.rgb = strokeRGBA.rgb; gl_FragColor = mix(fillRGBA, strokeRGBA, smoothstep( -uTroikaStrokeWidth - aaDist, -uTroikaStrokeWidth + aaDist, fragDistance )); gl_FragColor.a *= edgeAlpha; #endif if (edgeAlpha == 0.0) { discard; } `; /** * Create a material for rendering text, derived from a baseMaterial */ function createTextDerivedMaterial(baseMaterial) { const textMaterial = createDerivedMaterial(baseMaterial, { chained: true, extensions: { derivatives: true }, uniforms: { uTroikaSDFTexture: { value: null }, uTroikaSDFTextureSize: { value: new Vector2() }, uTroikaSDFGlyphSize: { value: 0 }, uTroikaSDFExponent: { value: 0 }, uTroikaTotalBounds: { value: new Vector4(0, 0, 0, 0) }, uTroikaClipRect: { value: new Vector4(0, 0, 0, 0) }, uTroikaEdgeOffset: { value: 0 }, uTroikaFillOpacity: { value: 1 }, uTroikaPositionOffset: { value: new Vector2() }, uTroikaCurveRadius: { value: 0 }, uTroikaBlurRadius: { value: 0 }, uTroikaStrokeWidth: { value: 0 }, uTroikaStrokeColor: { value: new Color() }, uTroikaStrokeOpacity: { value: 1 }, uTroikaOrient: { value: new Matrix3() }, uTroikaUseGlyphColors: { value: true }, uTroikaSDFDebug: { value: false } }, vertexDefs: VERTEX_DEFS, vertexTransform: VERTEX_TRANSFORM, fragmentDefs: FRAGMENT_DEFS, fragmentColorTransform: FRAGMENT_TRANSFORM, customRewriter({ vertexShader, fragmentShader }) { let uDiffuseRE = /\buniform\s+vec3\s+diffuse\b/; if (uDiffuseRE.test(fragmentShader)) { fragmentShader = fragmentShader.replace(uDiffuseRE, "varying vec3 vTroikaGlyphColor").replace(/\bdiffuse\b/g, "vTroikaGlyphColor"); if (!uDiffuseRE.test(vertexShader)) vertexShader = vertexShader.replace(voidMainRegExp, "uniform vec3 diffuse;\n$&\nvTroikaGlyphColor = uTroikaUseGlyphColors ? aTroikaGlyphColor / 255.0 : diffuse;\n"); } return { vertexShader, fragmentShader }; } }); textMaterial.transparent = true; textMaterial.forceSinglePass = true; Object.defineProperties(textMaterial, { isTroikaTextMaterial: { value: true }, shadowSide: { get() { return this.side; }, set() {} } }); return textMaterial; } var defaultMaterial = /*#__PURE__*/ new MeshBasicMaterial({ color: 16777215, side: 2, transparent: true }); var defaultStrokeColor = 8421504; var tempMat4 = /*#__PURE__*/ new Matrix4(); var tempVec3a = /*#__PURE__*/ new Vector3(); var tempVec3b = /*#__PURE__*/ new Vector3(); var tempArray = []; var origin = /*#__PURE__*/ new Vector3(); var defaultOrient = "+x+y"; function first(o) { return Array.isArray(o) ? o[0] : o; } var getFlatRaycastMesh = () => { const mesh = new Mesh(new PlaneGeometry(1, 1), defaultMaterial); getFlatRaycastMesh = () => mesh; return mesh; }; var getCurvedRaycastMesh = () => { const mesh = new Mesh(new PlaneGeometry(1, 1, 32, 1), defaultMaterial); getCurvedRaycastMesh = () => mesh; return mesh; }; var syncStartEvent = { type: "syncstart" }; var syncCompleteEvent = { type: "synccomplete" }; var SYNCABLE_PROPS = [ "font", "fontSize", "fontStyle", "fontWeight", "lang", "letterSpacing", "lineHeight", "maxWidth", "overflowWrap", "text", "direction", "textAlign", "textIndent", "whiteSpace", "anchorX", "anchorY", "colorRanges", "sdfGlyphSize" ]; var COPYABLE_PROPS = SYNCABLE_PROPS.concat("material", "color", "depthOffset", "clipRect", "curveRadius", "orientation", "glyphGeometryDetail"); /** * @class Text * * A ThreeJS Mesh that renders a string of text on a plane in 3D space using signed distance * fields (SDF). */ var Text$1 = class extends Mesh { constructor() { const geometry = new GlyphsGeometry(); super(geometry, null); /** * @member {string} text * The string of text to be rendered. */ this.text = ""; /** * @member {number|string} anchorX * Defines the horizontal position in the text block that should line up with the local origin. * Can be specified as a numeric x position in local units, a string percentage of the total * text block width e.g. `'25%'`, or one of the following keyword strings: 'left', 'center', * or 'right'. */ this.anchorX = 0; /** * @member {number|string} anchorY * Defines the vertical position in the text block that should line up with the local origin. * Can be specified as a numeric y position in local units (note: down is negative y), a string * percentage of the total text block height e.g. `'25%'`, or one of the following keyword strings: * 'top', 'top-baseline', 'top-cap', 'top-ex', 'middle', 'bottom-baseline', or 'bottom'. */ this.anchorY = 0; /** * @member {number} curveRadius * Defines a cylindrical radius along which the text's plane will be curved. Positive numbers put * the cylinder's centerline (oriented vertically) that distance in front of the text, for a concave * curvature, while negative numbers put it behind the text for a convex curvature. The centerline * will be aligned with the text's local origin; you can use `anchorX` to offset it. * * Since each glyph is by default rendered with a simple quad, each glyph remains a flat plane * internally. You can use `glyphGeometryDetail` to add more vertices for curvature inside glyphs. */ this.curveRadius = 0; /** * @member {string} direction * Sets the base direction for the text. The default value of "auto" will choose a direction based * on the text's content according to the bidi spec. A value of "ltr" or "rtl" will force the direction. */ this.direction = "auto"; /** * @member {string|null} font * URL of a custom font to be used. Font files can be in .ttf, .otf, or .woff (not .woff2) formats. * Defaults to Noto Sans. */ this.font = null; this.unicodeFontsURL = null; /** * @member {number} fontSize * The size at which to render the font in local units; corresponds to the em-box height * of the chosen `font`. */ this.fontSize = .1; /** * @member {number|'normal'|'bold'} * The weight of the font. Currently only used for fallback Noto fonts. */ this.fontWeight = "normal"; /** * @member {'normal'|'italic'} * The style of the font. Currently only used for fallback Noto fonts. */ this.fontStyle = "normal"; /** * @member {string|null} lang * The language code of this text; can be used for explicitly selecting certain CJK fonts. */ this.lang = null; /** * @member {number} letterSpacing * Sets a uniform adjustment to spacing between letters after kerning is applied. Positive * numbers increase spacing and negative numbers decrease it. */ this.letterSpacing = 0; /** * @member {number|string} lineHeight * Sets the height of each line of text, as a multiple of the `fontSize`. Defaults to 'normal' * which chooses a reasonable height based on the chosen font's ascender/descender metrics. */ this.lineHeight = "normal"; /** * @member {number} maxWidth * The maximum width of the text block, above which text may start wrapping according to the * `whiteSpace` and `overflowWrap` properties. */ this.maxWidth = Infinity; /** * @member {string} overflowWrap * Defines how text wraps if the `whiteSpace` property is `normal`. Can be either `'normal'` * to break at whitespace characters, or `'break-word'` to allow breaking within words. * Defaults to `'normal'`. */ this.overflowWrap = "normal"; /** * @member {string} textAlign * The horizontal alignment of each line of text within the overall text bounding box. */ this.textAlign = "left"; /** * @member {number} textIndent * Indentation for the first character of a line; see CSS `text-indent`. */ this.textIndent = 0; /** * @member {string} whiteSpace * Defines whether text should wrap when a line reaches the `maxWidth`. Can * be either `'normal'` (the default), to allow wrapping according to the `overflowWrap` property, * or `'nowrap'` to prevent wrapping. Note that `'normal'` here honors newline characters to * manually break lines, making it behave more like `'pre-wrap'` does in CSS. */ this.whiteSpace = "normal"; /** * @member {THREE.Material} material * Defines a _base_ material to be used when rendering the text. This material will be * automatically replaced with a material derived from it, that adds shader code to * decrease the alpha for each fragment (pixel) outside the text glyphs, with antialiasing. * By default it will derive from a simple white MeshBasicMaterial, but you can use any * of the other mesh materials to gain other features like lighting, texture maps, etc. * * Also see the `color` shortcut property. */ this.material = null; /** * @member {string|number|THREE.Color} color * This is a shortcut for setting the `color` of the text's material. You can use this * if you don't want to specify a whole custom `material`. Also, if you do use a custom * `material`, this color will only be used for this particuar Text instance, even if * that same material instance is shared across multiple Text objects. */ this.color = null; /** * @member {object|null} colorRanges * WARNING: This API is experimental and may change. * This allows more fine-grained control of colors for individual or ranges of characters, * taking precedence over the material's `color`. Its format is an Object whose keys each * define a starting character index for a range, and whose values are the color for each * range. The color value can be a numeric hex color value, a `THREE.Color` object, or * any of the strings accepted by `THREE.Color`. */ this.colorRanges = null; /** * @member {number|string} outlineWidth * WARNING: This API is experimental and may change. * The width of an outline/halo to be drawn around each text glyph using the `outlineColor` and `outlineOpacity`. * Can be specified as either an absolute number in local units, or as a percentage string e.g. * `"12%"` which is treated as a percentage of the `fontSize`. Defaults to `0`, which means * no outline will be drawn unless an `outlineOffsetX/Y` or `outlineBlur` is set. */ this.outlineWidth = 0; /** * @member {string|number|THREE.Color} outlineColor * WARNING: This API is experimental and may change. * The color of the text outline, if `outlineWidth`/`outlineBlur`/`outlineOffsetX/Y` are set. * Defaults to black. */ this.outlineColor = 0; /** * @member {number} outlineOpacity * WARNING: This API is experimental and may change. * The opacity of the outline, if `outlineWidth`/`outlineBlur`/`outlineOffsetX/Y` are set. * Defaults to `1`. */ this.outlineOpacity = 1; /** * @member {number|string} outlineBlur * WARNING: This API is experimental and may change. * A blur radius applied to the outer edge of the text's outline. If the `outlineWidth` is * zero, the blur will be applied at the glyph edge, like CSS's `text-shadow` blur radius. * Can be specified as either an absolute number in local units, or as a percentage string e.g. * `"12%"` which is treated as a percentage of the `fontSize`. Defaults to `0`. */ this.outlineBlur = 0; /** * @member {number|string} outlineOffsetX * WARNING: This API is experimental and may change. * A horizontal offset for the text outline. * Can be specified as either an absolute number in local units, or as a percentage string e.g. `"12%"` * which is treated as a percentage of the `fontSize`. Defaults to `0`. */ this.outlineOffsetX = 0; /** * @member {number|string} outlineOffsetY * WARNING: This API is experimental and may change. * A vertical offset for the text outline. * Can be specified as either an absolute number in local units, or as a percentage string e.g. `"12%"` * which is treated as a percentage of the `fontSize`. Defaults to `0`. */ this.outlineOffsetY = 0; /** * @member {number|string} strokeWidth * WARNING: This API is experimental and may change. * The width of an inner stroke drawn inside each text glyph using the `strokeColor` and `strokeOpacity`. * Can be specified as either an absolute number in local units, or as a percentage string e.g. `"12%"` * which is treated as a percentage of the `fontSize`. Defaults to `0`. */ this.strokeWidth = 0; /** * @member {string|number|THREE.Color} strokeColor * WARNING: This API is experimental and may change. * The color of the text stroke, if `strokeWidth` is greater than zero. Defaults to gray. */ this.strokeColor = defaultStrokeColor; /** * @member {number} strokeOpacity * WARNING: This API is experimental and may change. * The opacity of the stroke, if `strokeWidth` is greater than zero. Defaults to `1`. */ this.strokeOpacity = 1; /** * @member {number} fillOpacity * WARNING: This API is experimental and may change. * The opacity of the glyph's fill from 0 to 1. This behaves like the material's `opacity` but allows * giving the fill a different opacity than the `strokeOpacity`. A fillOpacity of `0` makes the * interior of the glyph invisible, leaving just the `strokeWidth`. Defaults to `1`. */ this.fillOpacity = 1; /** * @member {number} depthOffset * This is a shortcut for setting the material's `polygonOffset` and related properties, * which can be useful in preventing z-fighting when this text is laid on top of another * plane in the scene. Positive numbers are further from the camera, negatives closer. */ this.depthOffset = 0; /** * @member {Array} clipRect * If specified, defines a `[minX, minY, maxX, maxY]` of a rectangle outside of which all * pixels will be discarded. This can be used for example to clip overflowing text when * `whiteSpace='nowrap'`. */ this.clipRect = null; /** * @member {string} orientation * Defines the axis plane on which the text should be laid out when the mesh has no extra * rotation transform. It is specified as a string with two axes: the horizontal axis with * positive pointing right, and the vertical axis with positive pointing up. By default this * is '+x+y', meaning the text sits on the xy plane with the text's top toward positive y * and facing positive z. A value of '+x-z' would place it on the xz plane with the text's * top toward negative z and facing positive y. */ this.orientation = defaultOrient; /** * @member {number} glyphGeometryDetail * Controls number of vertical/horizontal segments that make up each glyph's rectangular * plane. Defaults to 1. This can be increased to provide more geometrical detail for custom * vertex shader effects, for example. */ this.glyphGeometryDetail = 1; /** * @member {number|null} sdfGlyphSize * The size of each glyph's SDF (signed distance field) used for rendering. This must be a * power-of-two number. Defaults to 64 which is generally a good balance of size and quality * for most fonts. Larger sizes can improve the quality of glyph rendering by increasing * the sharpness of corners and preventing loss of very thin lines, at the expense of * increased memory footprint and longer SDF generation time. */ this.sdfGlyphSize = null; /** * @member {boolean} gpuAccelerateSDF * When `true`, the SDF generation process will be GPU-accelerated with WebGL when possible, * making it much faster especially for complex glyphs, and falling back to a JavaScript version * executed in web workers when support isn't available. It should automatically detect support, * but it's still somewhat experimental, so you can set it to `false` to force it to use the JS * version if you encounter issues with it. */ this.gpuAccelerateSDF = true; this.debugSDF = false; } /** * Updates the text rendering according to the current text-related configuration properties. * This is an async process, so you can pass in a callback function to be executed when it * finishes. * @param {function} [callback] */ sync(callback) { if (this._needsSync) { this._needsSync = false; if (this._isSyncing) (this._queuedSyncs || (this._queuedSyncs = [])).push(callback); else { this._isSyncing = true; this.dispatchEvent(syncStartEvent); getTextRenderInfo({ text: this.text, font: this.font, lang: this.lang, fontSize: this.fontSize || .1, fontWeight: this.fontWeight || "normal", fontStyle: this.fontStyle || "normal", letterSpacing: this.letterSpacing || 0, lineHeight: this.lineHeight || "normal", maxWidth: this.maxWidth, direction: this.direction || "auto", textAlign: this.textAlign, textIndent: this.textIndent, whiteSpace: this.whiteSpace, overflowWrap: this.overflowWrap, anchorX: this.anchorX, anchorY: this.anchorY, colorRanges: this.colorRanges, includeCaretPositions: true, sdfGlyphSize: this.sdfGlyphSize, gpuAccelerateSDF: this.gpuAccelerateSDF, unicodeFontsURL: this.unicodeFontsURL }, (textRenderInfo) => { this._isSyncing = false; this._textRenderInfo = textRenderInfo; this.geometry.updateGlyphs(textRenderInfo.glyphBounds, textRenderInfo.glyphAtlasIndices, textRenderInfo.blockBounds, textRenderInfo.chunkedBounds, textRenderInfo.glyphColors); const queued = this._queuedSyncs; if (queued) { this._queuedSyncs = null; this._needsSync = true; this.sync(() => { queued.forEach((fn) => fn && fn()); }); } this.dispatchEvent(syncCompleteEvent); if (callback) callback(); }); } } } /** * Initiate a sync if needed - note it won't complete until next frame at the * earliest so if possible it's a good idea to call sync() manually as soon as * all the properties have been set. * @override */ onBeforeRender(renderer, scene, camera, geometry, material, group) { this.sync(); if (material.isTroikaTextMaterial) this._prepareForRender(material); } /** * Shortcut to dispose the geometry specific to this instance. * Note: we don't also dispose the derived material here because if anything else is * sharing the same base material it will result in a pause next frame as the program * is recompiled. Instead users can dispose the base material manually, like normal, * and we'll also dispose the derived material at that time. */ dispose() { this.geometry.dispose(); } /** * @property {TroikaTextRenderInfo|null} textRenderInfo * @readonly * The current processed rendering data for this TextMesh, returned by the TextBuilder after * a `sync()` call. This will be `null` initially, and may be stale for a short period until * the asynchrous `sync()` process completes. */ get textRenderInfo() { return this._textRenderInfo || null; } /** * Create the text derived material from the base material. Can be overridden to use a custom * derived material. */ createDerivedMaterial(baseMaterial) { return createTextDerivedMaterial(baseMaterial); } get material() { let derivedMaterial = this._derivedMaterial; const baseMaterial = this._baseMaterial || this._defaultMaterial || (this._defaultMaterial = defaultMaterial.clone()); if (!derivedMaterial || !derivedMaterial.isDerivedFrom(baseMaterial)) { derivedMaterial = this._derivedMaterial = this.createDerivedMaterial(baseMaterial); baseMaterial.addEventListener("dispose", function onDispose() { baseMaterial.removeEventListener("dispose", onDispose); derivedMaterial.dispose(); }); } if (this.hasOutline()) { let outlineMaterial = derivedMaterial._outlineMtl; if (!outlineMaterial) { outlineMaterial = derivedMaterial._outlineMtl = Object.create(derivedMaterial, { id: { value: derivedMaterial.id + .1 } }); outlineMaterial.isTextOutlineMaterial = true; outlineMaterial.depthWrite = false; outlineMaterial.map = null; derivedMaterial.addEventListener("dispose", function onDispose() { derivedMaterial.removeEventListener("dispose", onDispose); outlineMaterial.dispose(); }); } return [outlineMaterial, derivedMaterial]; } else return derivedMaterial; } set material(baseMaterial) { if (baseMaterial && baseMaterial.isTroikaTextMaterial) { this._derivedMaterial = baseMaterial; this._baseMaterial = baseMaterial.baseMaterial; } else this._baseMaterial = baseMaterial; } hasOutline() { return !!(this.outlineWidth || this.outlineBlur || this.outlineOffsetX || this.outlineOffsetY); } get glyphGeometryDetail() { return this.geometry.detail; } set glyphGeometryDetail(detail) { this.geometry.detail = detail; } get curveRadius() { return this.geometry.curveRadius; } set curveRadius(r) { this.geometry.curveRadius = r; } get customDepthMaterial() { return first(this.material).getDepthMaterial(); } set customDepthMaterial(m) {} get customDistanceMaterial() { return first(this.material).getDistanceMaterial(); } set customDistanceMaterial(m) {} _prepareForRender(material) { const isOutline = material.isTextOutlineMaterial; const uniforms = material.uniforms; const textInfo = this.textRenderInfo; if (textInfo) { const { sdfTexture, blockBounds } = textInfo; uniforms.uTroikaSDFTexture.value = sdfTexture; uniforms.uTroikaSDFTextureSize.value.set(sdfTexture.image.width, sdfTexture.image.height); uniforms.uTroikaSDFGlyphSize.value = textInfo.sdfGlyphSize; uniforms.uTroikaSDFExponent.value = textInfo.sdfExponent; uniforms.uTroikaTotalBounds.value.fromArray(blockBounds); uniforms.uTroikaUseGlyphColors.value = !isOutline && !!textInfo.glyphColors; let distanceOffset = 0; let blurRadius = 0; let strokeWidth = 0; let fillOpacity; let strokeOpacity; let strokeColor; let offsetX = 0; let offsetY = 0; if (isOutline) { let { outlineWidth, outlineOffsetX, outlineOffsetY, outlineBlur, outlineOpacity } = this; distanceOffset = this._parsePercent(outlineWidth) || 0; blurRadius = Math.max(0, this._parsePercent(outlineBlur) || 0); fillOpacity = outlineOpacity; offsetX = this._parsePercent(outlineOffsetX) || 0; offsetY = this._parsePercent(outlineOffsetY) || 0; } else { strokeWidth = Math.max(0, this._parsePercent(this.strokeWidth) || 0); if (strokeWidth) { strokeColor = this.strokeColor; uniforms.uTroikaStrokeColor.value.set(strokeColor == null ? defaultStrokeColor : strokeColor); strokeOpacity = this.strokeOpacity; if (strokeOpacity == null) strokeOpacity = 1; } fillOpacity = this.fillOpacity; } uniforms.uTroikaEdgeOffset.value = distanceOffset; uniforms.uTroikaPositionOffset.value.set(offsetX, offsetY); uniforms.uTroikaBlurRadius.value = blurRadius; uniforms.uTroikaStrokeWidth.value = strokeWidth; uniforms.uTroikaStrokeOpacity.value = strokeOpacity; uniforms.uTroikaFillOpacity.value = fillOpacity == null ? 1 : fillOpacity; uniforms.uTroikaCurveRadius.value = this.curveRadius || 0; let clipRect = this.clipRect; if (clipRect && Array.isArray(clipRect) && clipRect.length === 4) uniforms.uTroikaClipRect.value.fromArray(clipRect); else { const pad = (this.fontSize || .1) * 100; uniforms.uTroikaClipRect.value.set(blockBounds[0] - pad, blockBounds[1] - pad, blockBounds[2] + pad, blockBounds[3] + pad); } this.geometry.applyClipRect(uniforms.uTroikaClipRect.value); } uniforms.uTroikaSDFDebug.value = !!this.debugSDF; material.polygonOffset = !!this.depthOffset; material.polygonOffsetFactor = material.polygonOffsetUnits = this.depthOffset || 0; const color = isOutline ? this.outlineColor || 0 : this.color; if (color == null) delete material.color; else { const colorObj = material.hasOwnProperty("color") ? material.color : material.color = new Color(); if (color !== colorObj._input || typeof color === "object") colorObj.set(colorObj._input = color); } let orient = this.orientation || defaultOrient; if (orient !== material._orientation) { let rotMat = uniforms.uTroikaOrient.value; orient = orient.replace(/[^-+xyz]/g, ""); let match = orient !== defaultOrient && orient.match(/^([-+])([xyz])([-+])([xyz])$/); if (match) { let [, hSign, hAxis, vSign, vAxis] = match; tempVec3a.set(0, 0, 0)[hAxis] = hSign === "-" ? 1 : -1; tempVec3b.set(0, 0, 0)[vAxis] = vSign === "-" ? -1 : 1; tempMat4.lookAt(origin, tempVec3a.cross(tempVec3b), tempVec3b); rotMat.setFromMatrix4(tempMat4); } else rotMat.identity(); material._orientation = orient; } } _parsePercent(value) { if (typeof value === "string") { let match = value.match(/^(-?[\d.]+)%$/); let pct = match ? parseFloat(match[1]) : NaN; value = (isNaN(pct) ? 0 : pct / 100) * this.fontSize; } return value; } /** * Translate a point in local space to an x/y in the text plane. */ localPositionToTextCoords(position, target = new Vector2()) { target.copy(position); const r = this.curveRadius; if (r) target.x = Math.atan2(position.x, Math.abs(r) - Math.abs(position.z)) * Math.abs(r); return target; } /** * Translate a point in world space to an x/y in the text plane. */ worldPositionToTextCoords(position, target = new Vector2()) { tempVec3a.copy(position); return this.localPositionToTextCoords(this.worldToLocal(tempVec3a), target); } /** * @override Custom raycasting to test against the whole text block's max rectangular bounds * TODO is there any reason to make this more granular, like within individual line or glyph rects? */ raycast(raycaster, intersects) { const { textRenderInfo, curveRadius } = this; if (textRenderInfo) { const bounds = textRenderInfo.blockBounds; const raycastMesh = curveRadius ? getCurvedRaycastMesh() : getFlatRaycastMesh(); const geom = raycastMesh.geometry; const { position, uv } = geom.attributes; for (let i = 0; i < uv.count; i++) { let x = bounds[0] + uv.getX(i) * (bounds[2] - bounds[0]); const y = bounds[1] + uv.getY(i) * (bounds[3] - bounds[1]); let z = 0; if (curveRadius) { z = curveRadius - Math.cos(x / curveRadius) * curveRadius; x = Math.sin(x / curveRadius) * curveRadius; } position.setXYZ(i, x, y, z); } geom.boundingSphere = this.geometry.boundingSphere; geom.boundingBox = this.geometry.boundingBox; raycastMesh.matrixWorld = this.matrixWorld; raycastMesh.material.side = this.material.side; tempArray.length = 0; raycastMesh.raycast(raycaster, tempArray); for (let i = 0; i < tempArray.length; i++) { tempArray[i].object = this; intersects.push(tempArray[i]); } } } copy(source) { const geom = this.geometry; super.copy(source); this.geometry = geom; COPYABLE_PROPS.forEach((prop) => { this[prop] = source[prop]; }); return this; } clone() { return new this.constructor().copy(this); } }; SYNCABLE_PROPS.forEach((prop) => { const privateKey = "_private_" + prop; Object.defineProperty(Text$1.prototype, prop, { get() { return this[privateKey]; }, set(value) { if (value !== this[privateKey]) { this[privateKey] = value; this._needsSync = true; } } }); }); new Box3(); new Color(); //#endregion //#region node_modules/@react-three/drei/core/Text.js var Text = /* @__PURE__ */ import_react.forwardRef(({ sdfGlyphSize = 64, anchorX = "center", anchorY = "middle", font, fontSize = 1, children, characters, onSync, ...props }, ref) => { const invalidate = useThree(({ invalidate }) => invalidate); const [troikaMesh] = import_react.useState(() => new Text$1()); const [nodes, text] = import_react.useMemo(() => { const n = []; let t = ""; import_react.Children.forEach(children, (child) => { if (typeof child === "string" || typeof child === "number") t += child; else n.push(child); }); return [n, t]; }, [children]); suspend(() => new Promise((res) => preloadFont({ font, characters }, res)), [ "troika-text", font, characters ]); import_react.useLayoutEffect(() => void troikaMesh.sync(() => { invalidate(); if (onSync) onSync(troikaMesh); })); import_react.useEffect(() => { return () => troikaMesh.dispose(); }, [troikaMesh]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: troikaMesh, ref, font, text, anchorX, anchorY, fontSize, sdfGlyphSize }, props), nodes); }); //#endregion //#region node_modules/@react-three/drei/core/useFont.js var fontLoader = null; async function loadFontData(font) { return typeof font === "string" ? await (await fetch(font)).json() : font; } function parseFontData(fontData) { if (!fontLoader) fontLoader = new FontLoader(); return fontLoader.parse(fontData); } async function loader(font) { return parseFontData(await loadFontData(font)); } function useFont(font) { return suspend(loader, [font]); } useFont.preload = (font) => preload(loader, [font]); useFont.clear = (font) => clear$1([font]); //#endregion //#region node_modules/@react-three/drei/core/Text3D.js var types = ["string", "number"]; var getTextFromChildren = (children) => { let label = ""; const rest = []; import_react.Children.forEach(children, (child) => { if (types.includes(typeof child)) label += child + ""; else rest.push(child); }); return [label, ...rest]; }; var Text3D = /* @__PURE__ */ import_react.forwardRef(({ font: _font, letterSpacing = 0, lineHeight = 1, size = 1, height = .2, bevelThickness = .1, bevelSize = .01, bevelEnabled = false, bevelOffset = 0, bevelSegments = 4, curveSegments = 8, smooth, children, ...props }, fref) => { import_react.useMemo(() => extend({ RenamedTextGeometry: TextGeometry }), []); const ref = import_react.useRef(null); const font = useFont(_font); const opts = (0, import_react.useMemo)(() => { return { font, size, height, bevelThickness, bevelSize, bevelEnabled, bevelSegments, bevelOffset, curveSegments, letterSpacing, lineHeight }; }, [ font, size, height, bevelThickness, bevelSize, bevelEnabled, bevelSegments, bevelOffset, curveSegments, letterSpacing, lineHeight ]); /** * We need the `children` in the deps because we * need to be able to do `{state}`. */ const [label, ...rest] = (0, import_react.useMemo)(() => getTextFromChildren(children), [children]); const args = import_react.useMemo(() => [label, opts], [label, opts]); import_react.useLayoutEffect(() => { if (smooth) { ref.current.geometry = mergeVertices(ref.current.geometry, smooth); ref.current.geometry.computeVertexNormals(); } }, [args, smooth]); import_react.useImperativeHandle(fref, () => ref.current, []); return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({}, props, { ref }), /*#__PURE__*/ import_react.createElement("renamedTextGeometry", { args }), rest); }); //#endregion //#region node_modules/@react-three/drei/core/Effects.js var isWebGL2Available = () => { try { var canvas = document.createElement("canvas"); return !!(window.WebGL2RenderingContext && canvas.getContext("webgl2")); } catch (e) { return false; } }; var Effects = /* @__PURE__ */ import_react.forwardRef(({ children, multisamping = 8, renderIndex = 1, disableRender, disableGamma, disableRenderPass, depthBuffer = true, stencilBuffer = false, anisotropy = 1, colorSpace, type, ...props }, ref) => { import_react.useMemo(() => extend({ EffectComposer, RenderPass, ShaderPass }), []); const composer = import_react.useRef(null); import_react.useImperativeHandle(ref, () => composer.current, []); const { scene, camera, gl, size, viewport } = useThree(); const [target] = import_react.useState(() => { const t = new WebGLRenderTarget(size.width, size.height, { type: type || 1016, format: RGBAFormat, depthBuffer, stencilBuffer, anisotropy }); if (type === 1009 && colorSpace != null) t.texture.colorSpace = colorSpace; t.samples = multisamping; return t; }); import_react.useEffect(() => { var _composer$current, _composer$current2; (_composer$current = composer.current) == null || _composer$current.setSize(size.width, size.height); (_composer$current2 = composer.current) == null || _composer$current2.setPixelRatio(viewport.dpr); }, [ gl, size, viewport.dpr ]); useFrame(() => { var _composer$current3; if (!disableRender) (_composer$current3 = composer.current) == null || _composer$current3.render(); }, renderIndex); const passes = []; if (!disableRenderPass) passes.push(/*#__PURE__*/ import_react.createElement("renderPass", { key: "renderpass", attach: `passes-${passes.length}`, args: [scene, camera] })); if (!disableGamma) passes.push(/*#__PURE__*/ import_react.createElement("shaderPass", { attach: `passes-${passes.length}`, key: "gammapass", args: [GammaCorrectionShader] })); import_react.Children.forEach(children, (el) => { el && passes.push(/*#__PURE__*/ import_react.cloneElement(el, { key: passes.length, attach: `passes-${passes.length}` })); }); return /*#__PURE__*/ import_react.createElement("effectComposer", _extends$1({ ref: composer, args: [gl, target] }, props), passes); }); //#endregion //#region node_modules/@react-three/drei/core/GradientTexture.js var GradientType = /*#__PURE__*/ function(GradientType) { GradientType["Linear"] = "linear"; GradientType["Radial"] = "radial"; return GradientType; }({}); function GradientTexture({ stops, colors, size = 1024, width = 16, type = GradientType.Linear, innerCircleRadius = 0, outerCircleRadius = "auto", ...props }) { const gl = useThree((state) => state.gl); const canvas = import_react.useMemo(() => { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); canvas.width = width; canvas.height = size; let gradient; if (type === GradientType.Linear) gradient = context.createLinearGradient(0, 0, 0, size); else { const canvasCenterX = canvas.width / 2; const canvasCenterY = canvas.height / 2; const radius = outerCircleRadius !== "auto" ? Math.abs(Number(outerCircleRadius)) : Math.sqrt(canvasCenterX ** 2 + canvasCenterY ** 2); gradient = context.createRadialGradient(canvasCenterX, canvasCenterY, Math.abs(innerCircleRadius), canvasCenterX, canvasCenterY, radius); } const tempColor = new Color(); let i = stops.length; while (i--) gradient.addColorStop(stops[i], tempColor.set(colors[i]).getStyle()); context.save(); context.fillStyle = gradient; context.fillRect(0, 0, width, size); context.restore(); return canvas; }, [stops]); return /*#__PURE__*/ import_react.createElement("canvasTexture", _extends$1({ colorSpace: gl.outputColorSpace, args: [canvas], attach: "map" }, props)); } //#endregion //#region node_modules/@react-three/drei/core/shaderMaterial.js function shaderMaterial(uniforms, vertexShader, fragmentShader, onInit) { var _Class; return _Class = class extends ShaderMaterial { constructor(parameters) { super({ vertexShader, fragmentShader, ...parameters }); for (const key in uniforms) { this.uniforms[key] = new Uniform(uniforms[key]); Object.defineProperty(this, key, { get() { return this.uniforms[key].value; }, set(value) { this.uniforms[key].value = value; } }); } this.uniforms = UniformsUtils.clone(this.uniforms); onInit?.(this); } }, _Class.key = MathUtils.generateUUID(), _Class; } //#endregion //#region node_modules/@react-three/drei/core/Texture.js var IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function"; function useTexture(input, onLoad) { const gl = useThree((state) => state.gl); const textures = useLoader(TextureLoader, IsObject(input) ? Object.values(input) : input); (0, import_react.useLayoutEffect)(() => { onLoad?.(textures); }, [onLoad]); (0, import_react.useEffect)(() => { if ("initTexture" in gl) { let textureArray = []; if (Array.isArray(textures)) textureArray = textures; else if (textures instanceof Texture$1) textureArray = [textures]; else if (IsObject(textures)) textureArray = Object.values(textures); textureArray.forEach((texture) => { if (texture instanceof Texture$1) gl.initTexture(texture); }); } }, [gl, textures]); return (0, import_react.useMemo)(() => { if (IsObject(input)) { const keyed = {}; let i = 0; for (const key in input) keyed[key] = textures[i++]; return keyed; } else return textures; }, [input, textures]); } useTexture.preload = (url) => useLoader.preload(TextureLoader, url); useTexture.clear = (input) => useLoader.clear(TextureLoader, input); var Texture = ({ children, input, onLoad }) => { const ret = useTexture(input, onLoad); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(ret)); }; //#endregion //#region node_modules/@react-three/drei/helpers/constants.js var getVersion = () => parseInt("184".replace(/\D+/g, "")); var version$1 = /* @__PURE__ */ getVersion(); //#endregion //#region node_modules/@react-three/drei/core/Image.js var ImageMaterialImpl = /* @__PURE__ */ shaderMaterial({ color: /* @__PURE__ */ new Color("white"), scale: /* @__PURE__ */ new Vector2(1, 1), imageBounds: /* @__PURE__ */ new Vector2(1, 1), resolution: 1024, map: null, zoom: 1, radius: 0, grayscale: 0, opacity: 1 }, ` varying vec2 vUv; varying vec2 vPos; void main() { gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.); vUv = uv; vPos = position.xy; } `, ` // mostly from https://gist.github.com/statico/df64c5d167362ecf7b34fca0b1459a44 varying vec2 vUv; varying vec2 vPos; uniform vec2 scale; uniform vec2 imageBounds; uniform float resolution; uniform vec3 color; uniform sampler2D map; uniform float radius; uniform float zoom; uniform float grayscale; uniform float opacity; const vec3 luma = vec3(.299, 0.587, 0.114); vec4 toGrayscale(vec4 color, float intensity) { return vec4(mix(color.rgb, vec3(dot(color.rgb, luma)), intensity), color.a); } vec2 aspect(vec2 size) { return size / min(size.x, size.y); } const float PI = 3.14159265; // from https://iquilezles.org/articles/distfunctions float udRoundBox( vec2 p, vec2 b, float r ) { return length(max(abs(p)-b+r,0.0))-r; } void main() { vec2 s = aspect(scale); vec2 i = aspect(imageBounds); float rs = s.x / s.y; float ri = i.x / i.y; vec2 new = rs < ri ? vec2(i.x * s.y / i.y, s.y) : vec2(s.x, i.y * s.x / i.x); vec2 offset = (rs < ri ? vec2((new.x - s.x) / 2.0, 0.0) : vec2(0.0, (new.y - s.y) / 2.0)) / new; vec2 uv = vUv * s / new + offset; vec2 zUv = (uv - vec2(0.5, 0.5)) / zoom + vec2(0.5, 0.5); vec2 res = vec2(scale * resolution); vec2 halfRes = 0.5 * res; float b = udRoundBox(vUv.xy * res - halfRes, halfRes, resolution * radius); vec3 a = mix(vec3(1.0,0.0,0.0), vec3(0.0,0.0,0.0), smoothstep(0.0, 1.0, b)); gl_FragColor = toGrayscale(texture2D(map, zUv) * vec4(color, opacity * a), grayscale); #include #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } `); var ImageBase = /* @__PURE__ */ import_react.forwardRef(({ children, color, segments = 1, scale = 1, zoom = 1, grayscale = 0, opacity = 1, radius = 0, texture, toneMapped, transparent, side, ...props }, fref) => { extend({ ImageMaterial: ImageMaterialImpl }); const ref = import_react.useRef(null); const size = useThree((state) => state.size); const planeBounds = Array.isArray(scale) ? [scale[0], scale[1]] : [scale, scale]; const imageBounds = [texture.image.width, texture.image.height]; const resolution = Math.max(size.width, size.height); import_react.useImperativeHandle(fref, () => ref.current, []); import_react.useLayoutEffect(() => { if (ref.current.geometry.parameters) ref.current.material.scale.set(planeBounds[0] * ref.current.geometry.parameters.width, planeBounds[1] * ref.current.geometry.parameters.height); }, [planeBounds[0], planeBounds[1]]); return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref, scale: Array.isArray(scale) ? [...scale, 1] : scale }, props), /*#__PURE__*/ import_react.createElement("planeGeometry", { args: [ 1, 1, segments, segments ] }), /*#__PURE__*/ import_react.createElement("imageMaterial", { color, map: texture, zoom, grayscale, opacity, scale: planeBounds, imageBounds, resolution, radius, toneMapped, transparent, side, key: ImageMaterialImpl.key }), children); }); var ImageWithUrl = /* @__PURE__ */ import_react.forwardRef(({ url, ...props }, ref) => { const texture = useTexture(url); return /*#__PURE__*/ import_react.createElement(ImageBase, _extends$1({}, props, { texture, ref })); }); var ImageWithTexture = /* @__PURE__ */ import_react.forwardRef(({ url: _url, ...props }, ref) => { return /*#__PURE__*/ import_react.createElement(ImageBase, _extends$1({}, props, { ref })); }); var Image$1 = /* @__PURE__ */ import_react.forwardRef((props, ref) => { if (props.url) return /*#__PURE__*/ import_react.createElement(ImageWithUrl, _extends$1({}, props, { ref })); else if (props.texture) return /*#__PURE__*/ import_react.createElement(ImageWithTexture, _extends$1({}, props, { ref })); else throw new Error(" requires a url or texture"); }); //#endregion //#region node_modules/@react-three/drei/core/Edges.js var Edges = /* @__PURE__ */ import_react.forwardRef(({ threshold = 15, geometry: explicitGeometry, ...props }, fref) => { const ref = import_react.useRef(null); import_react.useImperativeHandle(fref, () => ref.current, []); const tmpPoints = import_react.useMemo(() => [ 0, 0, 0, 1, 0, 0 ], []); const memoizedGeometry = import_react.useRef(null); const memoizedThreshold = import_react.useRef(null); import_react.useLayoutEffect(() => { const parent = ref.current.parent; const geometry = explicitGeometry !== null && explicitGeometry !== void 0 ? explicitGeometry : parent == null ? void 0 : parent.geometry; if (!geometry) return; if (memoizedGeometry.current === geometry && memoizedThreshold.current === threshold) return; memoizedGeometry.current = geometry; memoizedThreshold.current = threshold; const points = new EdgesGeometry(geometry, threshold).attributes.position.array; ref.current.geometry.setPositions(points); ref.current.geometry.attributes.instanceStart.needsUpdate = true; ref.current.geometry.attributes.instanceEnd.needsUpdate = true; ref.current.computeLineDistances(); }); return /*#__PURE__*/ import_react.createElement(Line, _extends$1({ segments: true, points: tmpPoints, ref, raycast: () => null }, props)); }); //#endregion //#region node_modules/@react-three/drei/core/Outlines.js var OutlinesMaterial = /* @__PURE__ */ shaderMaterial({ screenspace: false, color: /* @__PURE__ */ new Color("black"), opacity: 1, thickness: .05, size: /* @__PURE__ */ new Vector2() }, `#include #include #include #include uniform float thickness; uniform bool screenspace; uniform vec2 size; void main() { #if defined (USE_SKINNING) #include #include #include #include #include #endif #include #include #include #include #include vec4 tNormal = vec4(normal, 0.0); vec4 tPosition = vec4(transformed, 1.0); #ifdef USE_INSTANCING tNormal = instanceMatrix * tNormal; tPosition = instanceMatrix * tPosition; #endif if (screenspace) { vec3 newPosition = tPosition.xyz + tNormal.xyz * thickness; gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); } else { vec4 clipPosition = projectionMatrix * modelViewMatrix * tPosition; vec4 clipNormal = projectionMatrix * modelViewMatrix * tNormal; vec2 offset = normalize(clipNormal.xy) * thickness / size * clipPosition.w * 2.0; clipPosition.xy += offset; gl_Position = clipPosition; } }`, `uniform vec3 color; uniform float opacity; #include void main(){ #include gl_FragColor = vec4(color, opacity); #include #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> }`); function Outlines({ color = "black", opacity = 1, transparent = false, screenspace = false, toneMapped = true, polygonOffset = false, polygonOffsetFactor = 0, renderOrder = 0, thickness = .05, angle = Math.PI, clippingPlanes, ...props }) { const ref = import_react.useRef(null); const [material] = import_react.useState(() => new OutlinesMaterial({ side: 1 })); const { gl } = useThree(); const contextSize = gl.getDrawingBufferSize(new Vector2()); import_react.useMemo(() => extend({ OutlinesMaterial }), []); const oldAngle = import_react.useRef(0); const oldGeometry = import_react.useRef(null); import_react.useLayoutEffect(() => { const group = ref.current; if (!group) return; const parent = group.parent; if (parent && parent.geometry) { if (oldAngle.current !== angle || oldGeometry.current !== parent.geometry) { var _group$children; oldAngle.current = angle; oldGeometry.current = parent.geometry; let mesh = (_group$children = group.children) == null ? void 0 : _group$children[0]; if (mesh) { if (angle) mesh.geometry.dispose(); group.remove(mesh); } if (parent.skeleton) { mesh = new SkinnedMesh(); mesh.material = material; mesh.bind(parent.skeleton, parent.bindMatrix); group.add(mesh); } else if (parent.isInstancedMesh) { mesh = new InstancedMesh(parent.geometry, material, parent.count); mesh.instanceMatrix = parent.instanceMatrix; group.add(mesh); } else { mesh = new Mesh(); mesh.material = material; group.add(mesh); } mesh.geometry = angle ? toCreasedNormals(parent.geometry, angle) : parent.geometry; mesh.morphTargetInfluences = parent.morphTargetInfluences; mesh.morphTargetDictionary = parent.morphTargetDictionary; } } }); import_react.useLayoutEffect(() => { const group = ref.current; if (!group) return; const mesh = group.children[0]; if (mesh) { mesh.renderOrder = renderOrder; const parent = group.parent; applyProps(mesh, { morphTargetInfluences: parent.morphTargetInfluences, morphTargetDictionary: parent.morphTargetDictionary }); applyProps(mesh.material, { transparent, thickness, color, opacity, size: contextSize, screenspace, toneMapped, polygonOffset, polygonOffsetFactor, clippingPlanes, clipping: clippingPlanes && clippingPlanes.length > 0 }); } }); import_react.useEffect(() => { return () => { const group = ref.current; if (!group) return; const mesh = group.children[0]; if (mesh) { if (angle) mesh.geometry.dispose(); group.remove(mesh); } }; }, []); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props)); } //#endregion //#region node_modules/meshline/dist/index.js var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; function memcpy(src, srcOffset, dst, dstOffset, length) { let i; src = src.subarray || src.slice ? src : src.buffer; dst = dst.subarray || dst.slice ? dst : dst.buffer; src = srcOffset ? src.subarray ? src.subarray(srcOffset, length && srcOffset + length) : src.slice(srcOffset, length && srcOffset + length) : src; if (dst.set) dst.set(src, dstOffset); else for (i = 0; i < src.length; i++) dst[i + dstOffset] = src[i]; return dst; } function convertPoints(points) { if (points instanceof Float32Array) return points; if (points instanceof BufferGeometry) return points.getAttribute("position").array; return points.map((p) => { const isArray = Array.isArray(p); return p instanceof Vector3 ? [ p.x, p.y, p.z ] : p instanceof Vector2 ? [ p.x, p.y, 0 ] : isArray && p.length === 3 ? [ p[0], p[1], p[2] ] : isArray && p.length === 2 ? [ p[0], p[1], 0 ] : p; }).flat(); } var MeshLineGeometry = class extends BufferGeometry { constructor() { super(); __publicField(this, "type", "MeshLine"); __publicField(this, "isMeshLine", true); __publicField(this, "positions", []); __publicField(this, "previous", []); __publicField(this, "next", []); __publicField(this, "side", []); __publicField(this, "width", []); __publicField(this, "indices_array", []); __publicField(this, "uvs", []); __publicField(this, "counters", []); __publicField(this, "widthCallback", null); __publicField(this, "_attributes"); __publicField(this, "_points", []); __publicField(this, "points"); __publicField(this, "matrixWorld", new Matrix4()); Object.defineProperties(this, { points: { enumerable: true, get() { return this._points; }, set(value) { this.setPoints(value, this.widthCallback); } } }); } setMatrixWorld(matrixWorld) { this.matrixWorld = matrixWorld; } setPoints(points, wcb) { points = convertPoints(points); this._points = points; this.widthCallback = wcb != null ? wcb : null; this.positions = []; this.counters = []; if (points.length && points[0] instanceof Vector3) for (let j = 0; j < points.length; j++) { const p = points[j]; const c = j / (points.length - 1); this.positions.push(p.x, p.y, p.z); this.positions.push(p.x, p.y, p.z); this.counters.push(c); this.counters.push(c); } else for (let j = 0; j < points.length; j += 3) { const c = j / (points.length - 1); this.positions.push(points[j], points[j + 1], points[j + 2]); this.positions.push(points[j], points[j + 1], points[j + 2]); this.counters.push(c); this.counters.push(c); } this.process(); } compareV3(a, b) { const aa = a * 6; const ab = b * 6; return this.positions[aa] === this.positions[ab] && this.positions[aa + 1] === this.positions[ab + 1] && this.positions[aa + 2] === this.positions[ab + 2]; } copyV3(a) { const aa = a * 6; return [ this.positions[aa], this.positions[aa + 1], this.positions[aa + 2] ]; } process() { const l = this.positions.length / 6; this.previous = []; this.next = []; this.side = []; this.width = []; this.indices_array = []; this.uvs = []; let w; let v; if (this.compareV3(0, l - 1)) v = this.copyV3(l - 2); else v = this.copyV3(0); this.previous.push(v[0], v[1], v[2]); this.previous.push(v[0], v[1], v[2]); for (let j = 0; j < l; j++) { this.side.push(1); this.side.push(-1); if (this.widthCallback) w = this.widthCallback(j / (l - 1)); else w = 1; this.width.push(w); this.width.push(w); this.uvs.push(j / (l - 1), 0); this.uvs.push(j / (l - 1), 1); if (j < l - 1) { v = this.copyV3(j); this.previous.push(v[0], v[1], v[2]); this.previous.push(v[0], v[1], v[2]); const n = j * 2; this.indices_array.push(n, n + 1, n + 2); this.indices_array.push(n + 2, n + 1, n + 3); } if (j > 0) { v = this.copyV3(j); this.next.push(v[0], v[1], v[2]); this.next.push(v[0], v[1], v[2]); } } if (this.compareV3(l - 1, 0)) v = this.copyV3(1); else v = this.copyV3(l - 1); this.next.push(v[0], v[1], v[2]); this.next.push(v[0], v[1], v[2]); if (!this._attributes || this._attributes.position.count !== this.counters.length) this._attributes = { position: new BufferAttribute(new Float32Array(this.positions), 3), previous: new BufferAttribute(new Float32Array(this.previous), 3), next: new BufferAttribute(new Float32Array(this.next), 3), side: new BufferAttribute(new Float32Array(this.side), 1), width: new BufferAttribute(new Float32Array(this.width), 1), uv: new BufferAttribute(new Float32Array(this.uvs), 2), index: new BufferAttribute(new Uint16Array(this.indices_array), 1), counters: new BufferAttribute(new Float32Array(this.counters), 1) }; else { this._attributes.position.copyArray(new Float32Array(this.positions)); this._attributes.position.needsUpdate = true; this._attributes.previous.copyArray(new Float32Array(this.previous)); this._attributes.previous.needsUpdate = true; this._attributes.next.copyArray(new Float32Array(this.next)); this._attributes.next.needsUpdate = true; this._attributes.side.copyArray(new Float32Array(this.side)); this._attributes.side.needsUpdate = true; this._attributes.width.copyArray(new Float32Array(this.width)); this._attributes.width.needsUpdate = true; this._attributes.uv.copyArray(new Float32Array(this.uvs)); this._attributes.uv.needsUpdate = true; this._attributes.index.copyArray(new Uint16Array(this.indices_array)); this._attributes.index.needsUpdate = true; } this.setAttribute("position", this._attributes.position); this.setAttribute("previous", this._attributes.previous); this.setAttribute("next", this._attributes.next); this.setAttribute("side", this._attributes.side); this.setAttribute("width", this._attributes.width); this.setAttribute("uv", this._attributes.uv); this.setAttribute("counters", this._attributes.counters); this.setAttribute("position", this._attributes.position); this.setAttribute("previous", this._attributes.previous); this.setAttribute("next", this._attributes.next); this.setAttribute("side", this._attributes.side); this.setAttribute("width", this._attributes.width); this.setAttribute("uv", this._attributes.uv); this.setAttribute("counters", this._attributes.counters); this.setIndex(this._attributes.index); this.computeBoundingSphere(); this.computeBoundingBox(); } advance({ x, y, z }) { const positions = this._attributes.position.array; const previous = this._attributes.previous.array; const next = this._attributes.next.array; const l = positions.length; memcpy(positions, 0, previous, 0, l); memcpy(positions, 6, positions, 0, l - 6); positions[l - 6] = x; positions[l - 5] = y; positions[l - 4] = z; positions[l - 3] = x; positions[l - 2] = y; positions[l - 1] = z; memcpy(positions, 6, next, 0, l - 6); next[l - 6] = x; next[l - 5] = y; next[l - 4] = z; next[l - 3] = x; next[l - 2] = y; next[l - 1] = z; this._attributes.position.needsUpdate = true; this._attributes.previous.needsUpdate = true; this._attributes.next.needsUpdate = true; } }; var vertexShader$1 = ` #include #include #include #include attribute vec3 previous; attribute vec3 next; attribute float side; attribute float width; attribute float counters; uniform vec2 resolution; uniform float lineWidth; uniform vec3 color; uniform float opacity; uniform float sizeAttenuation; varying vec2 vUV; varying vec4 vColor; varying float vCounters; vec2 fix(vec4 i, float aspect) { vec2 res = i.xy / i.w; res.x *= aspect; return res; } void main() { float aspect = resolution.x / resolution.y; vColor = vec4(color, opacity); vUV = uv; vCounters = counters; mat4 m = projectionMatrix * modelViewMatrix; vec4 finalPosition = m * vec4(position, 1.0) * aspect; vec4 prevPos = m * vec4(previous, 1.0); vec4 nextPos = m * vec4(next, 1.0); vec2 currentP = fix(finalPosition, aspect); vec2 prevP = fix(prevPos, aspect); vec2 nextP = fix(nextPos, aspect); float w = lineWidth * width; vec2 dir; if (nextP == currentP) dir = normalize(currentP - prevP); else if (prevP == currentP) dir = normalize(nextP - currentP); else { vec2 dir1 = normalize(currentP - prevP); vec2 dir2 = normalize(nextP - currentP); dir = normalize(dir1 + dir2); vec2 perp = vec2(-dir1.y, dir1.x); vec2 miter = vec2(-dir.y, dir.x); //w = clamp(w / dot(miter, perp), 0., 4. * lineWidth * width); } //vec2 normal = (cross(vec3(dir, 0.), vec3(0., 0., 1.))).xy; vec4 normal = vec4(-dir.y, dir.x, 0., 1.); normal.xy *= .5 * w; //normal *= projectionMatrix; if (sizeAttenuation == 0.) { normal.xy *= finalPosition.w; normal.xy /= (vec4(resolution, 0., 1.) * projectionMatrix).xy * aspect; } finalPosition.xy += normal.xy * side; gl_Position = finalPosition; #include #include vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); #include #include } `; var fragmentShader$1 = ` #include #include #include uniform sampler2D map; uniform sampler2D alphaMap; uniform float useGradient; uniform float useMap; uniform float useAlphaMap; uniform float useDash; uniform float dashArray; uniform float dashOffset; uniform float dashRatio; uniform float visibility; uniform float alphaTest; uniform vec2 repeat; uniform vec3 gradient[2]; varying vec2 vUV; varying vec4 vColor; varying float vCounters; void main() { #include vec4 diffuseColor = vColor; if (useGradient == 1.) diffuseColor = vec4(mix(gradient[0], gradient[1], vCounters), 1.0); if (useMap == 1.) diffuseColor *= texture2D(map, vUV * repeat); if (useAlphaMap == 1.) diffuseColor.a *= texture2D(alphaMap, vUV * repeat).a; if (diffuseColor.a < alphaTest) discard; if (useDash == 1.) diffuseColor.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio)); diffuseColor.a *= step(vCounters, visibility); #include gl_FragColor = diffuseColor; #include #include #include <${/* @__PURE__ */ (() => parseInt("184".replace(/\D+/g, "")))() >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } `; var MeshLineMaterial = class extends ShaderMaterial { constructor(parameters) { super({ uniforms: { ...UniformsLib.fog, lineWidth: { value: 1 }, map: { value: null }, useMap: { value: 0 }, alphaMap: { value: null }, useAlphaMap: { value: 0 }, color: { value: new Color(16777215) }, gradient: { value: [new Color(16711680), new Color(65280)] }, opacity: { value: 1 }, resolution: { value: new Vector2(1, 1) }, sizeAttenuation: { value: 1 }, dashArray: { value: 0 }, dashOffset: { value: 0 }, dashRatio: { value: .5 }, useDash: { value: 0 }, useGradient: { value: 0 }, visibility: { value: 1 }, alphaTest: { value: 0 }, repeat: { value: new Vector2(1, 1) } }, vertexShader: vertexShader$1, fragmentShader: fragmentShader$1 }); __publicField(this, "lineWidth"); __publicField(this, "map"); __publicField(this, "useMap"); __publicField(this, "alphaMap"); __publicField(this, "useAlphaMap"); __publicField(this, "color"); __publicField(this, "gradient"); __publicField(this, "resolution"); __publicField(this, "sizeAttenuation"); __publicField(this, "dashArray"); __publicField(this, "dashOffset"); __publicField(this, "dashRatio"); __publicField(this, "useDash"); __publicField(this, "useGradient"); __publicField(this, "visibility"); __publicField(this, "repeat"); this.type = "MeshLineMaterial"; Object.defineProperties(this, { lineWidth: { enumerable: true, get() { return this.uniforms.lineWidth.value; }, set(value) { this.uniforms.lineWidth.value = value; } }, map: { enumerable: true, get() { return this.uniforms.map.value; }, set(value) { this.uniforms.map.value = value; } }, useMap: { enumerable: true, get() { return this.uniforms.useMap.value; }, set(value) { this.uniforms.useMap.value = value; } }, alphaMap: { enumerable: true, get() { return this.uniforms.alphaMap.value; }, set(value) { this.uniforms.alphaMap.value = value; } }, useAlphaMap: { enumerable: true, get() { return this.uniforms.useAlphaMap.value; }, set(value) { this.uniforms.useAlphaMap.value = value; } }, color: { enumerable: true, get() { return this.uniforms.color.value; }, set(value) { this.uniforms.color.value = value; } }, gradient: { enumerable: true, get() { return this.uniforms.gradient.value; }, set(value) { this.uniforms.gradient.value = value; } }, opacity: { enumerable: true, get() { return this.uniforms.opacity.value; }, set(value) { this.uniforms.opacity.value = value; } }, resolution: { enumerable: true, get() { return this.uniforms.resolution.value; }, set(value) { this.uniforms.resolution.value.copy(value); } }, sizeAttenuation: { enumerable: true, get() { return this.uniforms.sizeAttenuation.value; }, set(value) { this.uniforms.sizeAttenuation.value = value; } }, dashArray: { enumerable: true, get() { return this.uniforms.dashArray.value; }, set(value) { this.uniforms.dashArray.value = value; this.useDash = value !== 0 ? 1 : 0; } }, dashOffset: { enumerable: true, get() { return this.uniforms.dashOffset.value; }, set(value) { this.uniforms.dashOffset.value = value; } }, dashRatio: { enumerable: true, get() { return this.uniforms.dashRatio.value; }, set(value) { this.uniforms.dashRatio.value = value; } }, useDash: { enumerable: true, get() { return this.uniforms.useDash.value; }, set(value) { this.uniforms.useDash.value = value; } }, useGradient: { enumerable: true, get() { return this.uniforms.useGradient.value; }, set(value) { this.uniforms.useGradient.value = value; } }, visibility: { enumerable: true, get() { return this.uniforms.visibility.value; }, set(value) { this.uniforms.visibility.value = value; } }, alphaTest: { enumerable: true, get() { return this.uniforms.alphaTest.value; }, set(value) { this.uniforms.alphaTest.value = value; } }, repeat: { enumerable: true, get() { return this.uniforms.repeat.value; }, set(value) { this.uniforms.repeat.value.copy(value); } } }); this.setValues(parameters); } copy(source) { super.copy(source); this.lineWidth = source.lineWidth; this.map = source.map; this.useMap = source.useMap; this.alphaMap = source.alphaMap; this.useAlphaMap = source.useAlphaMap; this.color.copy(source.color); this.gradient = source.gradient; this.opacity = source.opacity; this.resolution.copy(source.resolution); this.sizeAttenuation = source.sizeAttenuation; this.dashArray = source.dashArray; this.dashOffset = source.dashOffset; this.dashRatio = source.dashRatio; this.useDash = source.useDash; this.useGradient = source.useGradient; this.visibility = source.visibility; this.alphaTest = source.alphaTest; this.repeat.copy(source.repeat); return this; } }; //#endregion //#region node_modules/@react-three/drei/core/Trail.js var defaults$1 = { width: .2, length: 1, decay: 1, local: false, stride: 0, interval: 1 }; var shiftLeft = (collection, steps = 1) => { collection.set(collection.subarray(steps)); collection.fill(-Infinity, -steps); return collection; }; function useTrail(target, settings) { const { length, local, decay, interval, stride } = { ...defaults$1, ...settings }; const points = import_react.useRef(null); const [worldPosition] = import_react.useState(() => new Vector3()); import_react.useLayoutEffect(() => { if (target) points.current = Float32Array.from({ length: length * 10 * 3 }, (_, i) => target.position.getComponent(i % 3)); }, [length, target]); const prevPosition = import_react.useRef(new Vector3()); const frameCount = import_react.useRef(0); useFrame(() => { if (!target) return; if (!points.current) return; if (frameCount.current === 0) { let newPosition; if (local) newPosition = target.position; else { target.getWorldPosition(worldPosition); newPosition = worldPosition; } const steps = 1 * decay; for (let i = 0; i < steps; i++) { if (newPosition.distanceTo(prevPosition.current) < stride) continue; shiftLeft(points.current, 3); points.current.set(newPosition.toArray(), points.current.length - 3); } prevPosition.current.copy(newPosition); } frameCount.current++; frameCount.current = frameCount.current % interval; }); return points; } var Trail = /* @__PURE__ */ import_react.forwardRef((props, forwardRef) => { const { children } = props; const { width, length, decay, local, stride, interval } = { ...defaults$1, ...props }; const { color = "hotpink", attenuation, target } = props; const size = useThree((s) => s.size); const scene = useThree((s) => s.scene); const ref = import_react.useRef(null); const [anchor, setAnchor] = import_react.useState(null); const points = useTrail(anchor, { length, decay, local, stride, interval }); import_react.useEffect(() => { const t = (target == null ? void 0 : target.current) || ref.current.children.find((o) => { return o instanceof Object3D; }); if (t) setAnchor(t); }, [points, target]); const geo = import_react.useMemo(() => new MeshLineGeometry(), []); const mat = import_react.useMemo(() => { var _matOverride, _matOverride2; const m = new MeshLineMaterial({ lineWidth: .1 * width, color, sizeAttenuation: 1, resolution: new Vector2(size.width, size.height) }); let matOverride; if (children) if (Array.isArray(children)) matOverride = children.find((child) => { const c = child; return typeof c.type === "string" && c.type === "meshLineMaterial"; }); else { const c = children; if (typeof c.type === "string" && c.type === "meshLineMaterial") matOverride = c; } if (typeof ((_matOverride = matOverride) == null ? void 0 : _matOverride.props) === "object" && ((_matOverride2 = matOverride) == null ? void 0 : _matOverride2.props) !== null) m.setValues(matOverride.props); return m; }, [ width, color, size, children ]); import_react.useEffect(() => { mat.uniforms.resolution.value.set(size.width, size.height); }, [size]); useFrame(() => { if (!points.current) return; geo.setPoints(points.current, attenuation); }); return /*#__PURE__*/ import_react.createElement("group", null, createPortal(/*#__PURE__*/ import_react.createElement("mesh", { ref: forwardRef, geometry: geo, material: mat }), scene), /*#__PURE__*/ import_react.createElement("group", { ref }, children)); }); //#endregion //#region node_modules/@react-three/drei/core/Sampler.js function useSurfaceSampler(mesh, count = 16, transform, weight, instanceMesh) { const [buffer, setBuffer] = import_react.useState(() => { const arr = Array.from({ length: count }, () => [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]).flat(); return new InstancedBufferAttribute(Float32Array.from(arr), 16); }); import_react.useLayoutEffect(() => { if (typeof mesh.current === "undefined") return; const sampler = new MeshSurfaceSampler(mesh.current); if (weight) sampler.setWeightAttribute(weight); sampler.build(); const position = new Vector3(); const normal = new Vector3(); const color = new Color(); const dummy = new Object3D(); mesh.current.updateMatrixWorld(true); for (let i = 0; i < count; i++) { sampler.sample(position, normal, color); if (typeof transform === "function") transform({ dummy, sampledMesh: mesh.current, position, normal, color }, i); else dummy.position.copy(position); dummy.updateMatrix(); if (instanceMesh != null && instanceMesh.current) instanceMesh.current.setMatrixAt(i, dummy.matrix); dummy.matrix.toArray(buffer.array, i * 16); } if (instanceMesh != null && instanceMesh.current) instanceMesh.current.instanceMatrix.needsUpdate = true; buffer.needsUpdate = true; setBuffer(new InstancedBufferAttribute(buffer.array, buffer.itemSize).copy(buffer)); }, [ mesh, instanceMesh, weight, count, transform ]); return buffer; } function Sampler({ children, weight, transform, instances, mesh, count = 16, ...props }) { const group = import_react.useRef(null); const instancedRef = import_react.useRef(null); const meshToSampleRef = import_react.useRef(null); import_react.useLayoutEffect(() => { var _instances$current, _mesh$current; instancedRef.current = (_instances$current = instances == null ? void 0 : instances.current) !== null && _instances$current !== void 0 ? _instances$current : group.current.children.find((c) => c.hasOwnProperty("instanceMatrix")); meshToSampleRef.current = (_mesh$current = mesh == null ? void 0 : mesh.current) !== null && _mesh$current !== void 0 ? _mesh$current : group.current.children.find((c) => c.type === "Mesh"); }, [ children, mesh == null ? void 0 : mesh.current, instances == null ? void 0 : instances.current ]); useSurfaceSampler(meshToSampleRef, count, transform, weight, instancedRef); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: group }, props), children); } //#endregion //#region node_modules/@react-three/drei/core/ComputedAttribute.js /** * Used exclusively as a child of a BufferGeometry. * Computes the BufferAttribute by calling the `compute` function * and attaches the attribute to the geometry. */ var ComputedAttribute = ({ compute, name, ...props }) => { const [bufferAttribute] = import_react.useState(() => new BufferAttribute(new Float32Array(0), 1)); const primitive = import_react.useRef(null); import_react.useLayoutEffect(() => { if (primitive.current) { var _ref; const attr = compute((_ref = primitive.current.parent) !== null && _ref !== void 0 ? _ref : primitive.current.__r3f.parent.object); primitive.current.copy(attr); } }, [compute]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref: primitive, object: bufferAttribute, attach: `attributes-${name}` }, props)); }; //#endregion //#region node_modules/@react-three/drei/core/Clone.js function createSpread(child, { keys = [ "near", "far", "color", "distance", "decay", "penumbra", "angle", "intensity", "skeleton", "visible", "castShadow", "receiveShadow", "morphTargetDictionary", "morphTargetInfluences", "name", "geometry", "material", "position", "rotation", "scale", "up", "userData", "bindMode", "bindMatrix", "bindMatrixInverse", "skeleton" ], deep, inject, castShadow, receiveShadow }) { let spread = {}; for (const key of keys) spread[key] = child[key]; if (deep) { if (spread.geometry && deep !== "materialsOnly") spread.geometry = spread.geometry.clone(); if (spread.material && deep !== "geometriesOnly") spread.material = spread.material.clone(); } if (inject) if (typeof inject === "function") spread = { ...spread, children: inject(child) }; else if (/*#__PURE__*/ import_react.isValidElement(inject)) spread = { ...spread, children: inject }; else spread = { ...spread, ...inject }; if (child instanceof Mesh) { if (castShadow) spread.castShadow = true; if (receiveShadow) spread.receiveShadow = true; } return spread; } var Clone = /* @__PURE__ */ import_react.forwardRef(({ isChild = false, object, children, deep, castShadow, receiveShadow, inject, keys, ...props }, forwardRef) => { const config = { keys, deep, inject, castShadow, receiveShadow }; object = import_react.useMemo(() => { if (isChild === false && !Array.isArray(object)) { let isSkinned = false; object.traverse((object) => { if (object.isSkinnedMesh) isSkinned = true; }); if (isSkinned) return SkeletonUtils.clone(object); } return object; }, [object, isChild]); if (Array.isArray(object)) return /*#__PURE__*/ import_react.createElement("group", _extends$1({}, props, { ref: forwardRef }), object.map((o) => /*#__PURE__*/ import_react.createElement(Clone, _extends$1({ key: o.uuid, object: o }, config))), children); const { children: injectChildren, ...spread } = createSpread(object, config); const Element = object.type[0].toLowerCase() + object.type.slice(1); return /*#__PURE__*/ import_react.createElement(Element, _extends$1({}, spread, props, { ref: forwardRef }), object.children.map((child) => { if (child.type === "Bone") return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ key: child.uuid, object: child }, config)); return /*#__PURE__*/ import_react.createElement(Clone, _extends$1({ key: child.uuid, object: child }, config, { isChild: true })); }), children, injectChildren); }); //#endregion //#region node_modules/@react-three/drei/core/MarchingCubes.js var globalContext$1 = /* @__PURE__ */ import_react.createContext(null); var MarchingCubes = /* @__PURE__ */ import_react.forwardRef(({ resolution = 28, maxPolyCount = 1e4, enableUvs = false, enableColors = false, children, ...props }, ref) => { const marchingCubesRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => marchingCubesRef.current, []); const marchingCubes = import_react.useMemo(() => new MarchingCubes$1(resolution, null, enableUvs, enableColors, maxPolyCount), [ resolution, maxPolyCount, enableUvs, enableColors ]); const api = import_react.useMemo(() => ({ getParent: () => marchingCubesRef }), []); useFrame(() => { marchingCubes.update(); marchingCubes.reset(); }, -1); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: marchingCubes, ref: marchingCubesRef }, props), /*#__PURE__*/ import_react.createElement(globalContext$1.Provider, { value: api }, children))); }); var MarchingCube = /* @__PURE__ */ import_react.forwardRef(({ strength = .5, subtract = 12, color, ...props }, ref) => { const { getParent } = import_react.useContext(globalContext$1); const parentRef = import_react.useMemo(() => getParent(), [getParent]); const cubeRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => cubeRef.current, []); const vec = new Vector3(); useFrame((state) => { if (!parentRef.current || !cubeRef.current) return; cubeRef.current.getWorldPosition(vec); parentRef.current.addBall(.5 + vec.x * .5, .5 + vec.y * .5, .5 + vec.z * .5, strength, subtract, color); }); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: cubeRef }, props)); }); var MarchingPlane = /* @__PURE__ */ import_react.forwardRef(({ planeType: _planeType = "x", strength = .5, subtract = 12, ...props }, ref) => { const { getParent } = import_react.useContext(globalContext$1); const parentRef = import_react.useMemo(() => getParent(), [getParent]); const wallRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => wallRef.current, []); const planeType = import_react.useMemo(() => _planeType === "x" ? "addPlaneX" : _planeType === "y" ? "addPlaneY" : "addPlaneZ", [_planeType]); useFrame(() => { if (!parentRef.current || !wallRef.current) return; parentRef.current[planeType](strength, subtract); }); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: wallRef }, props)); }); //#endregion //#region node_modules/@react-three/drei/core/Decal.js function isArray$1(vec) { return Array.isArray(vec); } function vecToArray(vec = [ 0, 0, 0 ]) { if (isArray$1(vec)) return vec; else if (vec instanceof Vector3 || vec instanceof Euler) return [ vec.x, vec.y, vec.z ]; else return [ vec, vec, vec ]; } var Decal = /* @__PURE__ */ import_react.forwardRef(function Decal({ debug, depthTest = false, polygonOffsetFactor = -10, map, mesh, children, position, rotation, scale, ...props }, forwardRef) { const ref = import_react.useRef(null); import_react.useImperativeHandle(forwardRef, () => ref.current); const helper = import_react.useRef(null); const state = import_react.useRef({ position: new Vector3(), rotation: new Euler(), scale: new Vector3(1, 1, 1) }); import_react.useLayoutEffect(() => { const parent = (mesh == null ? void 0 : mesh.current) || ref.current.parent; const target = ref.current; if (!(parent instanceof Mesh)) throw new Error("Decal must have a Mesh as parent or specify its \"mesh\" prop"); if (parent) { applyProps(state.current, { position, scale }); const matrixWorld = parent.matrixWorld.clone(); parent.matrixWorld.identity(); if (!rotation || typeof rotation === "number") { const o = new Object3D(); o.position.copy(state.current.position); const vertices = parent.geometry.attributes.position.array; if (parent.geometry.attributes.normal === void 0) parent.geometry.computeVertexNormals(); const normal = parent.geometry.attributes.normal.array; let distance = Infinity; let closestNormal = new Vector3(); const ox = o.position.x; const oy = o.position.y; const oz = o.position.z; const vLength = vertices.length; let chosenIdx = -1; for (let i = 0; i < vLength; i += 3) { const x = vertices[i]; const y = vertices[i + 1]; const z = vertices[i + 2]; const xDiff = x - ox; const yDiff = y - oy; const zDiff = z - oz; const distSquared = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff; if (distSquared < distance) { distance = distSquared; chosenIdx = i; } } closestNormal.fromArray(normal, chosenIdx); o.lookAt(o.position.clone().add(closestNormal)); o.rotateZ(Math.PI); o.rotateY(Math.PI); if (typeof rotation === "number") o.rotateZ(rotation); applyProps(state.current, { rotation: o.rotation }); } else applyProps(state.current, { rotation }); if (helper.current) applyProps(helper.current, state.current); target.geometry = new DecalGeometry(parent, state.current.position, state.current.rotation, state.current.scale); parent.matrixWorld = matrixWorld; return () => { target.geometry.dispose(); }; } }, [ mesh, ...vecToArray(position), ...vecToArray(scale), ...vecToArray(rotation) ]); import_react.useLayoutEffect(() => { if (helper.current) helper.current.traverse((child) => child.raycast = () => null); }, [debug]); return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref, "material-transparent": true, "material-polygonOffset": true, "material-polygonOffsetFactor": polygonOffsetFactor, "material-depthTest": depthTest, "material-map": map }, props), children, debug && /*#__PURE__*/ import_react.createElement("mesh", { ref: helper }, /*#__PURE__*/ import_react.createElement("boxGeometry", null), /*#__PURE__*/ import_react.createElement("meshNormalMaterial", { wireframe: true }), /*#__PURE__*/ import_react.createElement("axesHelper", null))); }); //#endregion //#region node_modules/@react-three/drei/core/Svg.js var Svg = /* @__PURE__ */ (0, import_react.forwardRef)(function R3FSvg({ src, skipFill, skipStrokes, fillMaterial, strokeMaterial, fillMeshProps, strokeMeshProps, ...props }, ref) { const svg = useLoader(SVGLoader, !src.startsWith(" skipStrokes ? [] : svg.paths.map((path) => { var _path$userData; return ((_path$userData = path.userData) == null ? void 0 : _path$userData.style.stroke) === void 0 || path.userData.style.stroke === "none" ? null : path.subPaths.map((subPath) => SVGLoader.pointsToStroke(subPath.getPoints(), path.userData.style)); }), [svg, skipStrokes]); (0, import_react.useEffect)(() => { return () => strokeGeometries.forEach((group) => group && group.map((g) => g.dispose())); }, [strokeGeometries]); let renderOrder = 0; return /*#__PURE__*/ import_react.createElement("object3D", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement("object3D", { scale: [ 1, -1, 1 ] }, svg.paths.map((path, p) => { var _path$userData2, _path$userData3; return /*#__PURE__*/ import_react.createElement(import_react.Fragment, { key: p }, !skipFill && ((_path$userData2 = path.userData) == null ? void 0 : _path$userData2.style.fill) !== void 0 && path.userData.style.fill !== "none" && SVGLoader.createShapes(path).map((shape, s) => /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ key: s }, fillMeshProps, { renderOrder: renderOrder++ }), /*#__PURE__*/ import_react.createElement("shapeGeometry", { args: [shape] }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", _extends$1({ color: path.userData.style.fill, opacity: path.userData.style.fillOpacity, transparent: true, side: 2, depthWrite: false }, fillMaterial)))), !skipStrokes && ((_path$userData3 = path.userData) == null ? void 0 : _path$userData3.style.stroke) !== void 0 && path.userData.style.stroke !== "none" && path.subPaths.map((_subPath, s) => /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ key: s, geometry: strokeGeometries[p][s] }, strokeMeshProps, { renderOrder: renderOrder++ }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", _extends$1({ color: path.userData.style.stroke, opacity: path.userData.style.strokeOpacity, transparent: true, side: 2, depthWrite: false }, strokeMaterial))))); }))); }); //#endregion //#region node_modules/@react-three/drei/core/Gltf.js var dracoLoader = null; var decoderPath = "https://www.gstatic.com/draco/versioned/decoders/1.5.5/"; function extensions(useDraco = true, useMeshopt = true, extendLoader) { return (loader) => { if (extendLoader) extendLoader(loader); if (useDraco) { if (!dracoLoader) dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath(typeof useDraco === "string" ? useDraco : decoderPath); loader.setDRACOLoader(dracoLoader); } if (useMeshopt) loader.setMeshoptDecoder(typeof MeshoptDecoder === "function" ? MeshoptDecoder() : MeshoptDecoder); }; } var useGLTF = (path, useDraco, useMeshopt, extendLoader) => useLoader(GLTFLoader, path, extensions(useDraco, useMeshopt, extendLoader)); useGLTF.preload = (path, useDraco, useMeshopt, extendLoader) => useLoader.preload(GLTFLoader, path, extensions(useDraco, useMeshopt, extendLoader)); useGLTF.clear = (path) => useLoader.clear(GLTFLoader, path); useGLTF.setDecoderPath = (path) => { decoderPath = path; }; var Gltf = /* @__PURE__ */ import_react.forwardRef(({ src, useDraco, useMeshOpt, extendLoader, ...props }, ref) => { const { scene } = useGLTF(src, useDraco, useMeshOpt, extendLoader); return /*#__PURE__*/ import_react.createElement(Clone, _extends$1({ ref }, props, { object: scene })); }); //#endregion //#region node_modules/@react-three/drei/core/AsciiRenderer.js function AsciiRenderer({ renderIndex = 1, bgColor = "black", fgColor = "white", characters = " .:-+*=%@#", invert = true, color = false, resolution = .15 }) { const { size, gl, scene, camera } = useThree(); const effect = import_react.useMemo(() => { const effect = new AsciiEffect(gl, characters, { invert, color, resolution }); effect.domElement.style.position = "absolute"; effect.domElement.style.top = "0px"; effect.domElement.style.left = "0px"; effect.domElement.style.pointerEvents = "none"; return effect; }, [ characters, invert, color, resolution ]); import_react.useLayoutEffect(() => { effect.domElement.style.color = fgColor; effect.domElement.style.backgroundColor = bgColor; }, [fgColor, bgColor]); import_react.useEffect(() => { gl.domElement.style.opacity = "0"; gl.domElement.parentNode.appendChild(effect.domElement); return () => { gl.domElement.style.opacity = "1"; gl.domElement.parentNode.removeChild(effect.domElement); }; }, [effect]); import_react.useEffect(() => { effect.setSize(size.width, size.height); }, [effect, size]); useFrame((state) => { effect.render(scene, camera); }, renderIndex); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null); } //#endregion //#region node_modules/@react-three/drei/core/Splat.js var SplatMaterial = /* @__PURE__ */ shaderMaterial({ alphaTest: 0, viewport: /* @__PURE__ */ new Vector2(1980, 1080), focal: 1e3, centerAndScaleTexture: null, covAndColorTexture: null }, ` precision highp sampler2D; precision highp usampler2D; out vec4 vColor; out vec3 vPosition; uniform vec2 resolution; uniform vec2 viewport; uniform float focal; attribute uint splatIndex; uniform sampler2D centerAndScaleTexture; uniform usampler2D covAndColorTexture; vec2 unpackInt16(in uint value) { int v = int(value); int v0 = v >> 16; int v1 = (v & 0xFFFF); if((v & 0x8000) != 0) v1 |= 0xFFFF0000; return vec2(float(v1), float(v0)); } void main () { ivec2 texSize = textureSize(centerAndScaleTexture, 0); ivec2 texPos = ivec2(splatIndex%uint(texSize.x), splatIndex/uint(texSize.x)); vec4 centerAndScaleData = texelFetch(centerAndScaleTexture, texPos, 0); vec4 center = vec4(centerAndScaleData.xyz, 1); vec4 camspace = modelViewMatrix * center; vec4 pos2d = projectionMatrix * camspace; float bounds = 1.2 * pos2d.w; if (pos2d.z < -pos2d.w || pos2d.x < -bounds || pos2d.x > bounds || pos2d.y < -bounds || pos2d.y > bounds) { gl_Position = vec4(0.0, 0.0, 2.0, 1.0); return; } uvec4 covAndColorData = texelFetch(covAndColorTexture, texPos, 0); vec2 cov3D_M11_M12 = unpackInt16(covAndColorData.x) * centerAndScaleData.w; vec2 cov3D_M13_M22 = unpackInt16(covAndColorData.y) * centerAndScaleData.w; vec2 cov3D_M23_M33 = unpackInt16(covAndColorData.z) * centerAndScaleData.w; mat3 Vrk = mat3( cov3D_M11_M12.x, cov3D_M11_M12.y, cov3D_M13_M22.x, cov3D_M11_M12.y, cov3D_M13_M22.y, cov3D_M23_M33.x, cov3D_M13_M22.x, cov3D_M23_M33.x, cov3D_M23_M33.y ); mat3 J = mat3( focal / camspace.z, 0., -(focal * camspace.x) / (camspace.z * camspace.z), 0., focal / camspace.z, -(focal * camspace.y) / (camspace.z * camspace.z), 0., 0., 0. ); mat3 W = transpose(mat3(modelViewMatrix)); mat3 T = W * J; mat3 cov = transpose(T) * Vrk * T; vec2 vCenter = vec2(pos2d) / pos2d.w; float diagonal1 = cov[0][0] + 0.3; float offDiagonal = cov[0][1]; float diagonal2 = cov[1][1] + 0.3; float mid = 0.5 * (diagonal1 + diagonal2); float radius = length(vec2((diagonal1 - diagonal2) / 2.0, offDiagonal)); float lambda1 = mid + radius; float lambda2 = max(mid - radius, 0.1); vec2 diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1)); vec2 v1 = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector; vec2 v2 = min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x); uint colorUint = covAndColorData.w; vColor = vec4( float(colorUint & uint(0xFF)) / 255.0, float((colorUint >> uint(8)) & uint(0xFF)) / 255.0, float((colorUint >> uint(16)) & uint(0xFF)) / 255.0, float(colorUint >> uint(24)) / 255.0 ); vPosition = position; gl_Position = vec4( vCenter + position.x * v2 / viewport * 2.0 + position.y * v1 / viewport * 2.0, pos2d.z / pos2d.w, 1.0); } `, ` #include #include in vec4 vColor; in vec3 vPosition; void main () { float A = -dot(vPosition.xy, vPosition.xy); if (A < -4.0) discard; float B = exp(A) * vColor.a; vec4 diffuseColor = vec4(vColor.rgb, B); #include #include gl_FragColor = diffuseColor; #include #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } `); function createWorker(self) { let matrices = null; let offset = 0; function sortSplats(view, hashed = false) { const vertexCount = matrices.length / 16; const threshold = -1e-4; let maxDepth = -Infinity; let minDepth = Infinity; const depthList = new Float32Array(vertexCount); const sizeList = new Int32Array(depthList.buffer); const validIndexList = new Int32Array(vertexCount); let validCount = 0; for (let i = 0; i < vertexCount; i++) { const depth = view[0] * matrices[i * 16 + 12] + view[1] * matrices[i * 16 + 13] + view[2] * matrices[i * 16 + 14] + view[3]; if (hashed || depth < 0 && matrices[i * 16 + 15] > threshold * depth) { depthList[validCount] = depth; validIndexList[validCount] = i; validCount++; if (depth > maxDepth) maxDepth = depth; if (depth < minDepth) minDepth = depth; } } const depthInv = (256 * 256 - 1) / (maxDepth - minDepth); const counts0 = new Uint32Array(256 * 256); for (let i = 0; i < validCount; i++) { sizeList[i] = (depthList[i] - minDepth) * depthInv | 0; counts0[sizeList[i]]++; } const starts0 = new Uint32Array(256 * 256); for (let i = 1; i < 256 * 256; i++) starts0[i] = starts0[i - 1] + counts0[i - 1]; const depthIndex = new Uint32Array(validCount); for (let i = 0; i < validCount; i++) depthIndex[starts0[sizeList[i]]++] = validIndexList[i]; return depthIndex; } self.onmessage = (e) => { if (e.data.method == "push") { if (offset === 0) matrices = new Float32Array(e.data.length); const new_matrices = new Float32Array(e.data.matrices); matrices.set(new_matrices, offset); offset += new_matrices.length; } else if (e.data.method == "sort") { if (matrices !== null) { const indices = sortSplats(new Float32Array(e.data.view), e.data.hashed); self.postMessage({ indices, key: e.data.key }, [indices.buffer]); } } }; } var SplatLoader = class extends Loader$1 { constructor(...args) { super(...args); this.gl = null; this.chunkSize = 25e3; } load(url, onLoad, onProgress, onError) { const shared = { gl: this.gl, url: this.manager.resolveURL(url), worker: new Worker(URL.createObjectURL(new Blob([ "(", createWorker.toString(), ")(self)" ], { type: "application/javascript" }))), manager: this.manager, update: (target, camera, hashed) => update(camera, shared, target, hashed), connect: (target) => connect(shared, target), loading: false, loaded: false, loadedVertexCount: 0, chunkSize: this.chunkSize, totalDownloadBytes: 0, numVertices: 0, rowLength: 32, maxVertexes: 0, bufferTextureWidth: 0, bufferTextureHeight: 0, stream: null, centerAndScaleData: null, covAndColorData: null, covAndColorTexture: null, centerAndScaleTexture: null, onProgress }; load(shared).then(onLoad).catch((e) => { onError?.(e); shared.manager.itemError(shared.url); }); } }; async function load(shared) { shared.manager.itemStart(shared.url); const data = await fetch(shared.url); if (data.body === null) throw "Failed to fetch file"; let _totalDownloadBytes = data.headers.get("Content-Length"); const totalDownloadBytes = _totalDownloadBytes ? parseInt(_totalDownloadBytes) : void 0; if (totalDownloadBytes == void 0) throw "Failed to get content length"; shared.stream = data.body.getReader(); shared.totalDownloadBytes = totalDownloadBytes; shared.numVertices = Math.floor(shared.totalDownloadBytes / shared.rowLength); const context = shared.gl.getContext(); let maxTextureSize = context.getParameter(context.MAX_TEXTURE_SIZE); shared.maxVertexes = maxTextureSize * maxTextureSize; if (shared.numVertices > shared.maxVertexes) shared.numVertices = shared.maxVertexes; shared.bufferTextureWidth = maxTextureSize; shared.bufferTextureHeight = Math.floor((shared.numVertices - 1) / maxTextureSize) + 1; shared.centerAndScaleData = new Float32Array(shared.bufferTextureWidth * shared.bufferTextureHeight * 4); shared.covAndColorData = new Uint32Array(shared.bufferTextureWidth * shared.bufferTextureHeight * 4); shared.centerAndScaleTexture = new DataTexture(shared.centerAndScaleData, shared.bufferTextureWidth, shared.bufferTextureHeight, RGBAFormat, FloatType); shared.centerAndScaleTexture.needsUpdate = true; shared.covAndColorTexture = new DataTexture(shared.covAndColorData, shared.bufferTextureWidth, shared.bufferTextureHeight, RGBAIntegerFormat, UnsignedIntType); shared.covAndColorTexture.internalFormat = "RGBA32UI"; shared.covAndColorTexture.needsUpdate = true; return shared; } async function lazyLoad(shared) { shared.loading = true; let bytesDownloaded = 0; let bytesProcessed = 0; const chunks = []; let lastReportedProgress = 0; const lengthComputable = shared.totalDownloadBytes !== 0; while (true) try { const { value, done } = await shared.stream.read(); if (done) break; bytesDownloaded += value.length; if (shared.totalDownloadBytes != void 0) { const percent = bytesDownloaded / shared.totalDownloadBytes * 100; if (shared.onProgress && percent - lastReportedProgress > 1) { const event = new ProgressEvent("progress", { lengthComputable, loaded: bytesDownloaded, total: shared.totalDownloadBytes }); shared.onProgress(event); lastReportedProgress = percent; } } chunks.push(value); const bytesRemains = bytesDownloaded - bytesProcessed; if (shared.totalDownloadBytes != void 0 && bytesRemains > shared.rowLength * shared.chunkSize) { let vertexCount = Math.floor(bytesRemains / shared.rowLength); const concatenatedChunksbuffer = new Uint8Array(bytesRemains); let offset = 0; for (const chunk of chunks) { concatenatedChunksbuffer.set(chunk, offset); offset += chunk.length; } chunks.length = 0; if (bytesRemains > vertexCount * shared.rowLength) { const extra_data = new Uint8Array(bytesRemains - vertexCount * shared.rowLength); extra_data.set(concatenatedChunksbuffer.subarray(bytesRemains - extra_data.length, bytesRemains), 0); chunks.push(extra_data); } const buffer = new Uint8Array(vertexCount * shared.rowLength); buffer.set(concatenatedChunksbuffer.subarray(0, buffer.byteLength), 0); const matrices = pushDataBuffer(shared, buffer.buffer, vertexCount); shared.worker.postMessage({ method: "push", src: shared.url, length: shared.numVertices * 16, matrices: matrices.buffer }, [matrices.buffer]); bytesProcessed += vertexCount * shared.rowLength; if (shared.onProgress) { const event = new ProgressEvent("progress", { lengthComputable, loaded: shared.totalDownloadBytes, total: shared.totalDownloadBytes }); shared.onProgress(event); } } } catch (error) { console.error(error); break; } if (bytesDownloaded - bytesProcessed > 0) { let concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); let offset = 0; for (const chunk of chunks) { concatenatedChunks.set(chunk, offset); offset += chunk.length; } let numVertices = Math.floor(concatenatedChunks.byteLength / shared.rowLength); const matrices = pushDataBuffer(shared, concatenatedChunks.buffer, numVertices); shared.worker.postMessage({ method: "push", src: shared.url, length: numVertices * 16, matrices: matrices.buffer }, [matrices.buffer]); } shared.loaded = true; shared.manager.itemEnd(shared.url); } function update(camera, shared, target, hashed) { camera.updateMatrixWorld(); shared.gl.getCurrentViewport(target.viewport); target.material.viewport.x = target.viewport.z; target.material.viewport.y = target.viewport.w; target.material.focal = target.viewport.w / 2 * Math.abs(camera.projectionMatrix.elements[5]); if (target.ready) { if (hashed && target.sorted) return; target.ready = false; const view = new Float32Array([ target.modelViewMatrix.elements[2], -target.modelViewMatrix.elements[6], target.modelViewMatrix.elements[10], target.modelViewMatrix.elements[14] ]); shared.worker.postMessage({ method: "sort", src: shared.url, key: target.uuid, view: view.buffer, hashed }, [view.buffer]); if (hashed && shared.loaded) target.sorted = true; } } function connect(shared, target) { if (!shared.loading) lazyLoad(shared); target.ready = false; target.pm = new Matrix4(); target.vm1 = new Matrix4(); target.vm2 = new Matrix4(); target.viewport = new Vector4(); const splatIndexes = new InstancedBufferAttribute(new Uint32Array(shared.bufferTextureWidth * shared.bufferTextureHeight), 1, false); splatIndexes.setUsage(DynamicDrawUsage); const geometry = target.geometry = new InstancedBufferGeometry(); const positions = new BufferAttribute(new Float32Array(18), 3); geometry.setAttribute("position", positions); positions.setXYZ(2, -2, 2, 0); positions.setXYZ(1, 2, 2, 0); positions.setXYZ(0, -2, -2, 0); positions.setXYZ(5, -2, -2, 0); positions.setXYZ(4, 2, 2, 0); positions.setXYZ(3, 2, -2, 0); positions.needsUpdate = true; geometry.setAttribute("splatIndex", splatIndexes); geometry.instanceCount = 1; function listener(e) { if (target && e.data.key === target.uuid) { let indexes = new Uint32Array(e.data.indices); geometry.attributes.splatIndex.set(indexes); geometry.attributes.splatIndex.needsUpdate = true; geometry.instanceCount = indexes.length; target.ready = true; } } shared.worker.addEventListener("message", listener); async function wait() { while (true) { const centerAndScaleTextureProperties = shared.gl.properties.get(shared.centerAndScaleTexture); const covAndColorTextureProperties = shared.gl.properties.get(shared.covAndColorTexture); if (centerAndScaleTextureProperties != null && centerAndScaleTextureProperties.__webglTexture && covAndColorTextureProperties != null && covAndColorTextureProperties.__webglTexture && shared.loadedVertexCount > 0) break; await new Promise((resolve) => setTimeout(resolve, 10)); } target.ready = true; } wait(); return () => shared.worker.removeEventListener("message", listener); } function pushDataBuffer(shared, buffer, vertexCount) { const context = shared.gl.getContext(); if (shared.loadedVertexCount + vertexCount > shared.maxVertexes) vertexCount = shared.maxVertexes - shared.loadedVertexCount; if (vertexCount <= 0) throw "Failed to parse file"; const u_buffer = new Uint8Array(buffer); const f_buffer = new Float32Array(buffer); const matrices = new Float32Array(vertexCount * 16); const covAndColorData_uint8 = new Uint8Array(shared.covAndColorData.buffer); const covAndColorData_int16 = new Int16Array(shared.covAndColorData.buffer); for (let i = 0; i < vertexCount; i++) { const quat = new Quaternion(-(u_buffer[32 * i + 28 + 1] - 128) / 128, (u_buffer[32 * i + 28 + 2] - 128) / 128, (u_buffer[32 * i + 28 + 3] - 128) / 128, -(u_buffer[32 * i + 28 + 0] - 128) / 128); quat.invert(); const center = new Vector3(f_buffer[8 * i + 0], f_buffer[8 * i + 1], -f_buffer[8 * i + 2]); const scale = new Vector3(f_buffer[8 * i + 3 + 0], f_buffer[8 * i + 3 + 1], f_buffer[8 * i + 3 + 2]); const mtx = new Matrix4(); mtx.makeRotationFromQuaternion(quat); mtx.transpose(); mtx.scale(scale); const mtx_t = mtx.clone(); mtx.transpose(); mtx.premultiply(mtx_t); mtx.setPosition(center); const cov_indexes = [ 0, 1, 2, 5, 6, 10 ]; let max_value = 0; for (let j = 0; j < cov_indexes.length; j++) if (Math.abs(mtx.elements[cov_indexes[j]]) > max_value) max_value = Math.abs(mtx.elements[cov_indexes[j]]); let destOffset = shared.loadedVertexCount * 4 + i * 4; shared.centerAndScaleData[destOffset + 0] = center.x; shared.centerAndScaleData[destOffset + 1] = -center.y; shared.centerAndScaleData[destOffset + 2] = center.z; shared.centerAndScaleData[destOffset + 3] = max_value / 32767; destOffset = shared.loadedVertexCount * 8 + i * 4 * 2; for (let j = 0; j < cov_indexes.length; j++) covAndColorData_int16[destOffset + j] = mtx.elements[cov_indexes[j]] * 32767 / max_value; destOffset = shared.loadedVertexCount * 16 + (i * 4 + 3) * 4; const col = new Color(u_buffer[32 * i + 24 + 0] / 255, u_buffer[32 * i + 24 + 1] / 255, u_buffer[32 * i + 24 + 2] / 255); col.convertSRGBToLinear(); covAndColorData_uint8[destOffset + 0] = col.r * 255; covAndColorData_uint8[destOffset + 1] = col.g * 255; covAndColorData_uint8[destOffset + 2] = col.b * 255; covAndColorData_uint8[destOffset + 3] = u_buffer[32 * i + 24 + 3]; mtx.elements[15] = Math.max(scale.x, scale.y, scale.z) * u_buffer[32 * i + 24 + 3] / 255; for (let j = 0; j < 16; j++) matrices[i * 16 + j] = mtx.elements[j]; } while (vertexCount > 0) { let width = 0; let height = 0; const xoffset = shared.loadedVertexCount % shared.bufferTextureWidth; const yoffset = Math.floor(shared.loadedVertexCount / shared.bufferTextureWidth); if (shared.loadedVertexCount % shared.bufferTextureWidth != 0) { width = Math.min(shared.bufferTextureWidth, xoffset + vertexCount) - xoffset; height = 1; } else if (Math.floor(vertexCount / shared.bufferTextureWidth) > 0) { width = shared.bufferTextureWidth; height = Math.floor(vertexCount / shared.bufferTextureWidth); } else { width = vertexCount % shared.bufferTextureWidth; height = 1; } const centerAndScaleTextureProperties = shared.gl.properties.get(shared.centerAndScaleTexture); context.bindTexture(context.TEXTURE_2D, centerAndScaleTextureProperties.__webglTexture); context.texSubImage2D(context.TEXTURE_2D, 0, xoffset, yoffset, width, height, context.RGBA, context.FLOAT, shared.centerAndScaleData, shared.loadedVertexCount * 4); const covAndColorTextureProperties = shared.gl.properties.get(shared.covAndColorTexture); context.bindTexture(context.TEXTURE_2D, covAndColorTextureProperties.__webglTexture); context.texSubImage2D(context.TEXTURE_2D, 0, xoffset, yoffset, width, height, context.RGBA_INTEGER, context.UNSIGNED_INT, shared.covAndColorData, shared.loadedVertexCount * 4); shared.gl.resetState(); shared.loadedVertexCount += width * height; vertexCount -= width * height; } return matrices; } function Splat({ src, toneMapped = false, alphaTest = 0, alphaHash = false, chunkSize = 25e3, ...props }) { extend({ SplatMaterial }); const ref = import_react.useRef(null); const gl = useThree((state) => state.gl); const camera = useThree((state) => state.camera); const shared = useLoader(SplatLoader, src, (loader) => { loader.gl = gl; loader.chunkSize = chunkSize; }); import_react.useLayoutEffect(() => shared.connect(ref.current), [src]); useFrame(() => shared.update(ref.current, camera, alphaHash)); return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref, frustumCulled: false }, props), /*#__PURE__*/ import_react.createElement("splatMaterial", { key: `${src}/${alphaTest}/${alphaHash}${SplatMaterial.key}`, transparent: !alphaHash, depthTest: true, alphaTest: alphaHash ? 0 : alphaTest, centerAndScaleTexture: shared.centerAndScaleTexture, covAndColorTexture: shared.covAndColorTexture, depthWrite: alphaHash ? true : alphaTest > 0, blending: alphaHash ? 1 : 5, blendSrcAlpha: 201, alphaHash: !!alphaHash, toneMapped })); } //#endregion //#region node_modules/@react-three/drei/core/Fbo.js function useFBO(width, height, settings) { const size = useThree((state) => state.size); const viewport = useThree((state) => state.viewport); const _width = typeof width === "number" ? width : size.width * viewport.dpr; const _height = typeof height === "number" ? height : size.height * viewport.dpr; const _settings = (typeof width === "number" ? settings : width) || {}; const { samples = 0, depth, ...targetSettings } = _settings; const depthBuffer = depth !== null && depth !== void 0 ? depth : _settings.depthBuffer; const target = import_react.useMemo(() => { const target = new WebGLRenderTarget(_width, _height, { minFilter: LinearFilter, magFilter: LinearFilter, type: HalfFloatType, ...targetSettings }); if (depthBuffer) target.depthTexture = new DepthTexture(_width, _height, FloatType); target.samples = samples; return target; }, []); import_react.useLayoutEffect(() => { target.setSize(_width, _height); if (samples) target.samples = samples; }, [ samples, target, _width, _height ]); import_react.useEffect(() => { return () => target.dispose(); }, []); return target; } var Fbo = /* @__PURE__ */ (0, import_react.forwardRef)(({ children, width, height, ...settings }, fref) => { const target = useFBO(width, height, settings); (0, import_react.useImperativeHandle)(fref, () => target, [target]); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(target)); }); //#endregion //#region node_modules/@react-three/drei/core/OrthographicCamera.js var isFunction$1 = (node) => typeof node === "function"; var OrthographicCamera = /* @__PURE__ */ import_react.forwardRef(({ envMap, resolution = 256, frames = Infinity, children, makeDefault, ...props }, ref) => { const set = useThree(({ set }) => set); const camera = useThree(({ camera }) => camera); const size = useThree(({ size }) => size); const cameraRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => cameraRef.current, []); const groupRef = import_react.useRef(null); const fbo = useFBO(resolution); import_react.useLayoutEffect(() => { if (!props.manual) cameraRef.current.updateProjectionMatrix(); }, [size, props]); import_react.useLayoutEffect(() => { cameraRef.current.updateProjectionMatrix(); }); import_react.useLayoutEffect(() => { if (makeDefault) { const oldCam = camera; set(() => ({ camera: cameraRef.current })); return () => set(() => ({ camera: oldCam })); } }, [ cameraRef, makeDefault, set ]); let count = 0; let oldEnvMap = null; const functional = isFunction$1(children); useFrame((state) => { if (functional && (frames === Infinity || count < frames)) { groupRef.current.visible = false; state.gl.setRenderTarget(fbo); oldEnvMap = state.scene.background; if (envMap) state.scene.background = envMap; state.gl.render(state.scene, cameraRef.current); state.scene.background = oldEnvMap; state.gl.setRenderTarget(null); groupRef.current.visible = true; count++; } }); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("orthographicCamera", _extends$1({ left: size.width / -2, right: size.width / 2, top: size.height / 2, bottom: size.height / -2, ref: cameraRef }, props), !functional && children), /*#__PURE__*/ import_react.createElement("group", { ref: groupRef }, functional && children(fbo.texture))); }); //#endregion //#region node_modules/@react-three/drei/core/PerspectiveCamera.js var isFunction = (node) => typeof node === "function"; var PerspectiveCamera = /* @__PURE__ */ import_react.forwardRef(({ envMap, resolution = 256, frames = Infinity, makeDefault, children, ...props }, ref) => { const set = useThree(({ set }) => set); const camera = useThree(({ camera }) => camera); const size = useThree(({ size }) => size); const cameraRef = import_react.useRef(null); import_react.useImperativeHandle(ref, () => cameraRef.current, []); const groupRef = import_react.useRef(null); const fbo = useFBO(resolution); import_react.useLayoutEffect(() => { if (!props.manual) cameraRef.current.aspect = size.width / size.height; }, [size, props]); import_react.useLayoutEffect(() => { cameraRef.current.updateProjectionMatrix(); }); let count = 0; let oldEnvMap = null; const functional = isFunction(children); useFrame((state) => { if (functional && (frames === Infinity || count < frames)) { groupRef.current.visible = false; state.gl.setRenderTarget(fbo); oldEnvMap = state.scene.background; if (envMap) state.scene.background = envMap; state.gl.render(state.scene, cameraRef.current); state.scene.background = oldEnvMap; state.gl.setRenderTarget(null); groupRef.current.visible = true; count++; } }); import_react.useLayoutEffect(() => { if (makeDefault) { const oldCam = camera; set(() => ({ camera: cameraRef.current })); return () => set(() => ({ camera: oldCam })); } }, [ cameraRef, makeDefault, set ]); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("perspectiveCamera", _extends$1({ ref: cameraRef }, props), !functional && children), /*#__PURE__*/ import_react.createElement("group", { ref: groupRef }, functional && children(fbo.texture))); }); //#endregion //#region node_modules/@react-three/drei/core/CubeCamera.js function useCubeCamera({ resolution = 256, near = .1, far = 1e3, envMap, fog } = {}) { const gl = useThree(({ gl }) => gl); const scene = useThree(({ scene }) => scene); const fbo = (0, import_react.useMemo)(() => { const fbo = new WebGLCubeRenderTarget(resolution); fbo.texture.type = HalfFloatType; return fbo; }, [resolution]); (0, import_react.useEffect)(() => { return () => { fbo.dispose(); }; }, [fbo]); const camera = (0, import_react.useMemo)(() => new CubeCamera$1(near, far, fbo), [ near, far, fbo ]); let originalFog; let originalBackground; return { fbo, camera, update: import_react.useCallback(() => { originalFog = scene.fog; originalBackground = scene.background; scene.background = envMap || originalBackground; scene.fog = fog || originalFog; camera.update(gl, scene); scene.fog = originalFog; scene.background = originalBackground; }, [ gl, scene, camera ]) }; } function CubeCamera({ children, frames = Infinity, resolution, near, far, envMap, fog, ...props }) { const ref = import_react.useRef(null); const { fbo, camera, update } = useCubeCamera({ resolution, near, far, envMap, fog }); let count = 0; useFrame(() => { if (ref.current && (frames === Infinity || count < frames)) { ref.current.visible = false; update(); ref.current.visible = true; count++; } }); return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement("primitive", { object: camera }), /*#__PURE__*/ import_react.createElement("group", { ref }, children == null ? void 0 : children(fbo.texture))); } //#endregion //#region node_modules/@react-three/drei/core/DeviceOrientationControls.js var DeviceOrientationControls = /* @__PURE__ */ import_react.forwardRef((props, ref) => { const { camera, onChange, makeDefault, ...rest } = props; const defaultCamera = useThree((state) => state.camera); const invalidate = useThree((state) => state.invalidate); const get = useThree((state) => state.get); const set = useThree((state) => state.set); const explCamera = camera || defaultCamera; const controls = import_react.useMemo(() => new DeviceOrientationControls$1(explCamera), [explCamera]); import_react.useEffect(() => { const callback = (e) => { invalidate(); if (onChange) onChange(e); }; controls == null || controls.addEventListener == null || controls.addEventListener("change", callback); return () => controls == null || controls.removeEventListener == null ? void 0 : controls.removeEventListener("change", callback); }, [ onChange, controls, invalidate ]); useFrame(() => controls == null ? void 0 : controls.update(), -1); import_react.useEffect(() => { const current = controls; current?.connect(); return () => current == null ? void 0 : current.dispose(); }, [controls]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return controls ? /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, rest)) : null; }); //#endregion //#region node_modules/@react-three/drei/core/FlyControls.js var FlyControls = /* @__PURE__ */ import_react.forwardRef(({ domElement, ...props }, fref) => { const { onChange, makeDefault, ...rest } = props; const invalidate = useThree((state) => state.invalidate); const camera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const get = useThree((state) => state.get); const set = useThree((state) => state.set); const explDomElement = domElement || events.connected || gl.domElement; const controls = import_react.useMemo(() => new FlyControls$1(camera), [camera]); import_react.useEffect(() => { controls.connect(explDomElement); return () => void controls.dispose(); }, [ explDomElement, controls, invalidate ]); import_react.useEffect(() => { const callback = (e) => { invalidate(); if (onChange) onChange(e); }; controls.addEventListener == null || controls.addEventListener("change", callback); return () => controls.removeEventListener == null ? void 0 : controls.removeEventListener("change", callback); }, [onChange, invalidate]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); useFrame((_, delta) => controls.update(delta)); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref: fref, object: controls, args: [camera, explDomElement] }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/MapControls.js var MapControls = /* @__PURE__ */ import_react.forwardRef((props = { enableDamping: true }, ref) => { const { domElement, camera, makeDefault, onChange, onStart, onEnd, ...rest } = props; const invalidate = useThree((state) => state.invalidate); const defaultCamera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const set = useThree((state) => state.set); const get = useThree((state) => state.get); const explDomElement = domElement || events.connected || gl.domElement; const explCamera = camera || defaultCamera; const controls = import_react.useMemo(() => new MapControls$1(explCamera), [explCamera]); import_react.useEffect(() => { controls.connect(explDomElement); const callback = (e) => { invalidate(); if (onChange) onChange(e); }; controls.addEventListener("change", callback); if (onStart) controls.addEventListener("start", onStart); if (onEnd) controls.addEventListener("end", onEnd); return () => { controls.dispose(); controls.removeEventListener("change", callback); if (onStart) controls.removeEventListener("start", onStart); if (onEnd) controls.removeEventListener("end", onEnd); }; }, [ onChange, onStart, onEnd, controls, invalidate, explDomElement ]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); useFrame(() => controls.update(), -1); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls, enableDamping: true }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/OrbitControls.js var OrbitControls = /* @__PURE__ */ import_react.forwardRef(({ makeDefault, camera, regress, domElement, enableDamping = true, keyEvents = false, onChange, onStart, onEnd, ...restProps }, ref) => { const invalidate = useThree((state) => state.invalidate); const defaultCamera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const setEvents = useThree((state) => state.setEvents); const set = useThree((state) => state.set); const get = useThree((state) => state.get); const performance = useThree((state) => state.performance); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = import_react.useMemo(() => new OrbitControls$1(explCamera), [explCamera]); useFrame(() => { if (controls.enabled) controls.update(); }, -1); import_react.useEffect(() => { if (keyEvents) controls.connect(keyEvents === true ? explDomElement : keyEvents); controls.connect(explDomElement); return () => void controls.dispose(); }, [ keyEvents, explDomElement, regress, controls, invalidate ]); import_react.useEffect(() => { const callback = (e) => { invalidate(); if (regress) performance.regress(); if (onChange) onChange(e); }; const onStartCb = (e) => { if (onStart) onStart(e); }; const onEndCb = (e) => { if (onEnd) onEnd(e); }; controls.addEventListener("change", callback); controls.addEventListener("start", onStartCb); controls.addEventListener("end", onEndCb); return () => { controls.removeEventListener("start", onStartCb); controls.removeEventListener("end", onEndCb); controls.removeEventListener("change", callback); }; }, [ onChange, onStart, onEnd, controls, invalidate, setEvents ]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls, enableDamping }, restProps)); }); //#endregion //#region node_modules/@react-three/drei/core/TrackballControls.js var TrackballControls = /* @__PURE__ */ import_react.forwardRef(({ makeDefault, camera, domElement, regress, onChange, onStart, onEnd, ...restProps }, ref) => { const { invalidate, camera: defaultCamera, gl, events, set, get, performance, viewport } = useThree(); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = import_react.useMemo(() => new TrackballControls$1(explCamera), [explCamera]); useFrame(() => { if (controls.enabled) controls.update(); }, -1); import_react.useEffect(() => { controls.connect(explDomElement); return () => void controls.dispose(); }, [ explDomElement, regress, controls, invalidate ]); import_react.useEffect(() => { const callback = (e) => { invalidate(); if (regress) performance.regress(); if (onChange) onChange(e); }; controls.addEventListener("change", callback); if (onStart) controls.addEventListener("start", onStart); if (onEnd) controls.addEventListener("end", onEnd); return () => { if (onStart) controls.removeEventListener("start", onStart); if (onEnd) controls.removeEventListener("end", onEnd); controls.removeEventListener("change", callback); }; }, [ onChange, onStart, onEnd, controls, invalidate ]); import_react.useEffect(() => { controls.handleResize(); }, [viewport]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, restProps)); }); //#endregion //#region node_modules/@react-three/drei/core/ArcballControls.js var ArcballControls = /* @__PURE__ */ (0, import_react.forwardRef)(({ camera, makeDefault, regress, domElement, onChange, onStart, onEnd, ...restProps }, ref) => { const invalidate = useThree((state) => state.invalidate); const defaultCamera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const set = useThree((state) => state.set); const get = useThree((state) => state.get); const performance = useThree((state) => state.performance); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = (0, import_react.useMemo)(() => new ArcballControls$1(explCamera), [explCamera]); useFrame(() => { if (controls.enabled) controls.update(); }, -1); (0, import_react.useEffect)(() => { controls.connect(explDomElement); return () => void controls.dispose(); }, [ explDomElement, regress, controls, invalidate ]); (0, import_react.useEffect)(() => { const callback = (e) => { invalidate(); if (regress) performance.regress(); if (onChange) onChange(e); }; controls.addEventListener("change", callback); if (onStart) controls.addEventListener("start", onStart); if (onEnd) controls.addEventListener("end", onEnd); return () => { controls.removeEventListener("change", callback); if (onStart) controls.removeEventListener("start", onStart); if (onEnd) controls.removeEventListener("end", onEnd); }; }, [ onChange, onStart, onEnd ]); (0, import_react.useEffect)(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, restProps)); }); //#endregion //#region node_modules/@react-three/drei/core/TransformControls.js var TransformControls = /* @__PURE__ */ import_react.forwardRef(({ children, domElement, onChange, onMouseDown, onMouseUp, onObjectChange, object, makeDefault, camera, enabled, axis, mode, translationSnap, rotationSnap, scaleSnap, space, size, showX, showY, showZ, ...props }, ref) => { const defaultControls = useThree((state) => state.controls); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const defaultCamera = useThree((state) => state.camera); const invalidate = useThree((state) => state.invalidate); const get = useThree((state) => state.get); const set = useThree((state) => state.set); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = import_react.useMemo(() => new TransformControls$1(explCamera, explDomElement), [explCamera, explDomElement]); const group = import_react.useRef(null); import_react.useLayoutEffect(() => { if (object) controls.attach(object instanceof Object3D ? object : object.current); else if (group.current instanceof Object3D) controls.attach(group.current); return () => void controls.detach(); }, [ object, children, controls ]); import_react.useEffect(() => { if (defaultControls) { const callback = (event) => defaultControls.enabled = !event.value; controls.addEventListener("dragging-changed", callback); return () => controls.removeEventListener("dragging-changed", callback); } }, [controls, defaultControls]); const onChangeRef = import_react.useRef(void 0); const onMouseDownRef = import_react.useRef(void 0); const onMouseUpRef = import_react.useRef(void 0); const onObjectChangeRef = import_react.useRef(void 0); import_react.useLayoutEffect(() => void (onChangeRef.current = onChange), [onChange]); import_react.useLayoutEffect(() => void (onMouseDownRef.current = onMouseDown), [onMouseDown]); import_react.useLayoutEffect(() => void (onMouseUpRef.current = onMouseUp), [onMouseUp]); import_react.useLayoutEffect(() => void (onObjectChangeRef.current = onObjectChange), [onObjectChange]); import_react.useEffect(() => { const onChange = (e) => { invalidate(); onChangeRef.current == null || onChangeRef.current(e); }; const onMouseDown = (e) => onMouseDownRef.current == null ? void 0 : onMouseDownRef.current(e); const onMouseUp = (e) => onMouseUpRef.current == null ? void 0 : onMouseUpRef.current(e); const onObjectChange = (e) => onObjectChangeRef.current == null ? void 0 : onObjectChangeRef.current(e); controls.addEventListener("change", onChange); controls.addEventListener("mouseDown", onMouseDown); controls.addEventListener("mouseUp", onMouseUp); controls.addEventListener("objectChange", onObjectChange); return () => { controls.removeEventListener("change", onChange); controls.removeEventListener("mouseDown", onMouseDown); controls.removeEventListener("mouseUp", onMouseUp); controls.removeEventListener("objectChange", onObjectChange); }; }, [invalidate, controls]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("primitive", { ref, object: controls, enabled, axis, mode, translationSnap, rotationSnap, scaleSnap, space, size, showX, showY, showZ }), /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: group }, props), children)); }); //#endregion //#region node_modules/@react-three/drei/core/PointerLockControls.js var PointerLockControls = /* @__PURE__ */ import_react.forwardRef(({ domElement, selector, onChange, onLock, onUnlock, enabled = true, makeDefault, ...props }, ref) => { const { camera, ...rest } = props; const setEvents = useThree((state) => state.setEvents); const gl = useThree((state) => state.gl); const defaultCamera = useThree((state) => state.camera); const invalidate = useThree((state) => state.invalidate); const events = useThree((state) => state.events); const get = useThree((state) => state.get); const set = useThree((state) => state.set); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = import_react.useMemo(() => new PointerLockControls$1(explCamera), [explCamera]); import_react.useEffect(() => { if (enabled) { controls.connect(explDomElement); const oldComputeOffsets = get().events.compute; setEvents({ compute(event, state) { const offsetX = state.size.width / 2; const offsetY = state.size.height / 2; state.pointer.set(offsetX / state.size.width * 2 - 1, -(offsetY / state.size.height) * 2 + 1); state.raycaster.setFromCamera(state.pointer, state.camera); } }); return () => { controls.disconnect(); setEvents({ compute: oldComputeOffsets }); }; } }, [enabled, controls]); import_react.useEffect(() => { const callback = (e) => { invalidate(); if (onChange) onChange(e); }; controls.addEventListener("change", callback); if (onLock) controls.addEventListener("lock", onLock); if (onUnlock) controls.addEventListener("unlock", onUnlock); const handler = () => controls.lock(); const elements = selector ? Array.from(document.querySelectorAll(selector)) : [document]; elements.forEach((element) => element && element.addEventListener("click", handler)); return () => { controls.removeEventListener("change", callback); if (onLock) controls.removeEventListener("lock", onLock); if (onUnlock) controls.removeEventListener("unlock", onUnlock); elements.forEach((element) => element ? element.removeEventListener("click", handler) : void 0); }; }, [ onChange, onLock, onUnlock, selector, controls, invalidate ]); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, rest)); }); //#endregion //#region node_modules/@react-three/drei/core/FirstPersonControls.js var FirstPersonControls = /* @__PURE__ */ import_react.forwardRef(({ domElement, makeDefault, ...props }, ref) => { const camera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const events = useThree((state) => state.events); const get = useThree((state) => state.get); const set = useThree((state) => state.set); const explDomElement = domElement || events.connected || gl.domElement; const [controls] = import_react.useState(() => new FirstPersonControls$1(camera, explDomElement)); import_react.useEffect(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); useFrame((_, delta) => { controls.update(delta); }, -1); return controls ? /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, props)) : null; }); //#endregion //#region node_modules/camera-controls/dist/camera-controls.module.js /*! * camera-controls * https://github.com/yomotsu/camera-controls * (c) 2017 @yomotsu * Released under the MIT License. */ var MOUSE_BUTTON = { LEFT: 1, RIGHT: 2, MIDDLE: 4 }; var ACTION = Object.freeze({ NONE: 0, ROTATE: 1, TRUCK: 2, SCREEN_PAN: 4, OFFSET: 8, DOLLY: 16, ZOOM: 32, TOUCH_ROTATE: 64, TOUCH_TRUCK: 128, TOUCH_SCREEN_PAN: 256, TOUCH_OFFSET: 512, TOUCH_DOLLY: 1024, TOUCH_ZOOM: 2048, TOUCH_DOLLY_TRUCK: 4096, TOUCH_DOLLY_SCREEN_PAN: 8192, TOUCH_DOLLY_OFFSET: 16384, TOUCH_DOLLY_ROTATE: 32768, TOUCH_ZOOM_TRUCK: 65536, TOUCH_ZOOM_OFFSET: 131072, TOUCH_ZOOM_SCREEN_PAN: 262144, TOUCH_ZOOM_ROTATE: 524288 }); var DOLLY_DIRECTION = { NONE: 0, IN: 1, OUT: -1 }; function isPerspectiveCamera(camera) { return camera.isPerspectiveCamera; } function isOrthographicCamera$1(camera) { return camera.isOrthographicCamera; } var PI_2 = Math.PI * 2; var PI_HALF = Math.PI / 2; var EPSILON = 1e-5; var DEG2RAD = Math.PI / 180; function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } function approxZero(number, error = EPSILON) { return Math.abs(number) < error; } function approxEquals(a, b, error = EPSILON) { return approxZero(a - b, error); } function roundToStep(value, step) { return Math.round(value / step) * step; } function infinityToMaxNumber(value) { if (isFinite(value)) return value; if (value < 0) return -Number.MAX_VALUE; return Number.MAX_VALUE; } function maxNumberToInfinity(value) { if (Math.abs(value) < Number.MAX_VALUE) return value; return value * Infinity; } function smoothDamp(current, target, currentVelocityRef, smoothTime, maxSpeed = Infinity, deltaTime) { smoothTime = Math.max(1e-4, smoothTime); const omega = 2 / smoothTime; const x = omega * deltaTime; const exp = 1 / (1 + x + .48 * x * x + .235 * x * x * x); let change = current - target; const originalTo = target; const maxChange = maxSpeed * smoothTime; change = clamp(change, -maxChange, maxChange); target = current - change; const temp = (currentVelocityRef.value + omega * change) * deltaTime; currentVelocityRef.value = (currentVelocityRef.value - omega * temp) * exp; let output = target + (change + temp) * exp; if (originalTo - current > 0 === output > originalTo) { output = originalTo; currentVelocityRef.value = (output - originalTo) / deltaTime; } return output; } function smoothDampVec3(current, target, currentVelocityRef, smoothTime, maxSpeed = Infinity, deltaTime, out) { smoothTime = Math.max(1e-4, smoothTime); const omega = 2 / smoothTime; const x = omega * deltaTime; const exp = 1 / (1 + x + .48 * x * x + .235 * x * x * x); let targetX = target.x; let targetY = target.y; let targetZ = target.z; let changeX = current.x - targetX; let changeY = current.y - targetY; let changeZ = current.z - targetZ; const originalToX = targetX; const originalToY = targetY; const originalToZ = targetZ; const maxChange = maxSpeed * smoothTime; const maxChangeSq = maxChange * maxChange; const magnitudeSq = changeX * changeX + changeY * changeY + changeZ * changeZ; if (magnitudeSq > maxChangeSq) { const magnitude = Math.sqrt(magnitudeSq); changeX = changeX / magnitude * maxChange; changeY = changeY / magnitude * maxChange; changeZ = changeZ / magnitude * maxChange; } targetX = current.x - changeX; targetY = current.y - changeY; targetZ = current.z - changeZ; const tempX = (currentVelocityRef.x + omega * changeX) * deltaTime; const tempY = (currentVelocityRef.y + omega * changeY) * deltaTime; const tempZ = (currentVelocityRef.z + omega * changeZ) * deltaTime; currentVelocityRef.x = (currentVelocityRef.x - omega * tempX) * exp; currentVelocityRef.y = (currentVelocityRef.y - omega * tempY) * exp; currentVelocityRef.z = (currentVelocityRef.z - omega * tempZ) * exp; out.x = targetX + (changeX + tempX) * exp; out.y = targetY + (changeY + tempY) * exp; out.z = targetZ + (changeZ + tempZ) * exp; const origMinusCurrentX = originalToX - current.x; const origMinusCurrentY = originalToY - current.y; const origMinusCurrentZ = originalToZ - current.z; const outMinusOrigX = out.x - originalToX; const outMinusOrigY = out.y - originalToY; const outMinusOrigZ = out.z - originalToZ; if (origMinusCurrentX * outMinusOrigX + origMinusCurrentY * outMinusOrigY + origMinusCurrentZ * outMinusOrigZ > 0) { out.x = originalToX; out.y = originalToY; out.z = originalToZ; currentVelocityRef.x = (out.x - originalToX) / deltaTime; currentVelocityRef.y = (out.y - originalToY) / deltaTime; currentVelocityRef.z = (out.z - originalToZ) / deltaTime; } return out; } function extractClientCoordFromEvent(pointers, out) { out.set(0, 0); pointers.forEach((pointer) => { out.x += pointer.clientX; out.y += pointer.clientY; }); out.x /= pointers.length; out.y /= pointers.length; } function notSupportedInOrthographicCamera(camera, message) { if (isOrthographicCamera$1(camera)) { console.warn(`${message} is not supported in OrthographicCamera`); return true; } return false; } var EventDispatcher = class { _listeners = {}; /** * Adds the specified event listener. * @param type event name * @param listener handler function * @category Methods */ addEventListener(type, listener) { const listeners = this._listeners; if (listeners[type] === void 0) listeners[type] = []; if (listeners[type].indexOf(listener) === -1) listeners[type].push(listener); } /** * Presence of the specified event listener. * @param type event name * @param listener handler function * @category Methods */ hasEventListener(type, listener) { const listeners = this._listeners; return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1; } /** * Removes the specified event listener * @param type event name * @param listener handler function * @category Methods */ removeEventListener(type, listener) { const listenerArray = this._listeners[type]; if (listenerArray !== void 0) { const index = listenerArray.indexOf(listener); if (index !== -1) listenerArray.splice(index, 1); } } /** * Removes all event listeners * @param type event name * @category Methods */ removeAllEventListeners(type) { if (!type) { this._listeners = {}; return; } if (Array.isArray(this._listeners[type])) this._listeners[type].length = 0; } /** * Fire an event type. * @param event DispatcherEvent * @category Methods */ dispatchEvent(event) { const listenerArray = this._listeners[event.type]; if (listenerArray !== void 0) { event.target = this; const array = listenerArray.slice(0); for (let i = 0, l = array.length; i < l; i++) array[i].call(this, event); } } }; var VERSION = "3.1.2"; var TOUCH_DOLLY_FACTOR = 1 / 8; var isMac = /Mac/.test(globalThis?.navigator?.platform); var THREE; var _ORIGIN; var _AXIS_Y; var _AXIS_Z; var _v2; var _v3A; var _v3B; var _v3C; var _cameraDirection; var _xColumn; var _yColumn; var _zColumn; var _deltaTarget; var _deltaOffset; var _sphericalA; var _sphericalB; var _box3A; var _box3B; var _sphere$2; var _quaternionA; var _quaternionB; var _rotationMatrix; var _raycaster; var CameraControls$1 = class CameraControls$1 extends EventDispatcher { /** * Injects THREE as the dependency. You can then proceed to use CameraControls. * * e.g * ```javascript * CameraControls.install( { THREE: THREE } ); * ``` * * Note: If you do not wish to use enter three.js to reduce file size(tree-shaking for example), make a subset to install. * * ```js * import { * Vector2, * Vector3, * Vector4, * Quaternion, * Matrix4, * Spherical, * Box3, * Sphere, * Raycaster, * MathUtils, * } from 'three'; * * const subsetOfTHREE = { * Vector2 : Vector2, * Vector3 : Vector3, * Vector4 : Vector4, * Quaternion: Quaternion, * Matrix4 : Matrix4, * Spherical : Spherical, * Box3 : Box3, * Sphere : Sphere, * Raycaster : Raycaster, * }; * CameraControls.install( { THREE: subsetOfTHREE } ); * ``` * @category Statics */ static install(libs) { THREE = libs.THREE; _ORIGIN = Object.freeze(new THREE.Vector3(0, 0, 0)); _AXIS_Y = Object.freeze(new THREE.Vector3(0, 1, 0)); _AXIS_Z = Object.freeze(new THREE.Vector3(0, 0, 1)); _v2 = new THREE.Vector2(); _v3A = new THREE.Vector3(); _v3B = new THREE.Vector3(); _v3C = new THREE.Vector3(); _cameraDirection = new THREE.Vector3(); _xColumn = new THREE.Vector3(); _yColumn = new THREE.Vector3(); _zColumn = new THREE.Vector3(); _deltaTarget = new THREE.Vector3(); _deltaOffset = new THREE.Vector3(); _sphericalA = new THREE.Spherical(); _sphericalB = new THREE.Spherical(); _box3A = new THREE.Box3(); _box3B = new THREE.Box3(); _sphere$2 = new THREE.Sphere(); _quaternionA = new THREE.Quaternion(); _quaternionB = new THREE.Quaternion(); _rotationMatrix = new THREE.Matrix4(); _raycaster = new THREE.Raycaster(); } /** * list all ACTIONs * @category Statics */ static get ACTION() { return ACTION; } /** * Minimum vertical angle in radians. * The angle has to be between `0` and `.maxPolarAngle` inclusive. * The default value is `0`. * * e.g. * ``` * cameraControls.maxPolarAngle = 0; * ``` * @category Properties */ minPolarAngle = 0; /** * Maximum vertical angle in radians. * The angle has to be between `.maxPolarAngle` and `Math.PI` inclusive. * The default value is `Math.PI`. * * e.g. * ``` * cameraControls.maxPolarAngle = Math.PI; * ``` * @category Properties */ maxPolarAngle = Math.PI; /** * Minimum horizontal angle in radians. * The angle has to be less than `.maxAzimuthAngle`. * The default value is `- Infinity`. * * e.g. * ``` * cameraControls.minAzimuthAngle = - Infinity; * ``` * @category Properties */ minAzimuthAngle = -Infinity; /** * Maximum horizontal angle in radians. * The angle has to be greater than `.minAzimuthAngle`. * The default value is `Infinity`. * * e.g. * ``` * cameraControls.maxAzimuthAngle = Infinity; * ``` * @category Properties */ maxAzimuthAngle = Infinity; /** * Minimum distance for dolly. The value must be higher than `0`. Default is `Number.EPSILON`. * PerspectiveCamera only. * @category Properties */ minDistance = Number.EPSILON; /** * Maximum distance for dolly. The value must be higher than `minDistance`. Default is `Infinity`. * PerspectiveCamera only. * @category Properties */ maxDistance = Infinity; /** * `true` to enable Infinity Dolly for wheel and pinch. Use this with `minDistance` and `maxDistance` * If the Dolly distance is less (or over) than the `minDistance` (or `maxDistance`), `infinityDolly` will keep the distance and pushes the target position instead. * @category Properties */ infinityDolly = false; /** * Minimum camera zoom. * @category Properties */ minZoom = .01; /** * Maximum camera zoom. * @category Properties */ maxZoom = Infinity; /** * Approximate time in seconds to reach the target. A smaller value will reach the target faster. * @category Properties */ smoothTime = .25; /** * the smoothTime while dragging * @category Properties */ draggingSmoothTime = .125; /** * Max transition speed in unit-per-seconds * @category Properties */ maxSpeed = Infinity; /** * Speed of azimuth (horizontal) rotation. * @category Properties */ azimuthRotateSpeed = 1; /** * Speed of polar (vertical) rotation. * @category Properties */ polarRotateSpeed = 1; /** * Speed of mouse-wheel dollying. * @category Properties */ dollySpeed = 1; /** * `true` to invert direction when dollying or zooming via drag * @category Properties */ dollyDragInverted = false; /** * Speed of drag for truck and pedestal. * @category Properties */ truckSpeed = 2; /** * `true` to enable Dolly-in to the mouse cursor coords. * @category Properties */ dollyToCursor = false; /** * @category Properties */ dragToOffset = false; /** * Friction ratio of the boundary. * @category Properties */ boundaryFriction = 0; /** * Controls how soon the `rest` event fires as the camera slows. * @category Properties */ restThreshold = .01; /** * An array of Meshes to collide with camera. * Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners. * @category Properties */ colliderMeshes = []; /** * User's mouse input config. * * | button to assign | behavior | * | --------------------- | -------- | * | `mouseButtons.left` | `CameraControls.ACTION.ROTATE`* \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` | * | `mouseButtons.right` | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK`* \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` | * | `mouseButtons.wheel` ¹ | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY` \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` | * | `mouseButtons.middle` ² | `CameraControls.ACTION.ROTATE` \| `CameraControls.ACTION.TRUCK` \| `CameraControls.ACTION.OFFSET` \| `CameraControls.ACTION.DOLLY`* \| `CameraControls.ACTION.ZOOM` \| `CameraControls.ACTION.NONE` | * * 1. Mouse wheel event for scroll "up/down" on mac "up/down/left/right" * 2. Mouse click on wheel event "button" * - \* is the default. * - The default of `mouseButtons.wheel` is: * - `DOLLY` for Perspective camera. * - `ZOOM` for Orthographic camera, and can't set `DOLLY`. * @category Properties */ mouseButtons; /** * User's touch input config. * * | fingers to assign | behavior | * | --------------------- | -------- | * | `touches.one` | `CameraControls.ACTION.TOUCH_ROTATE`* \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.DOLLY` | `CameraControls.ACTION.ZOOM` | `CameraControls.ACTION.NONE` | * | `touches.two` | `ACTION.TOUCH_DOLLY_TRUCK` \| `ACTION.TOUCH_DOLLY_OFFSET` \| `ACTION.TOUCH_DOLLY_ROTATE` \| `ACTION.TOUCH_ZOOM_TRUCK` \| `ACTION.TOUCH_ZOOM_OFFSET` \| `ACTION.TOUCH_ZOOM_ROTATE` \| `ACTION.TOUCH_DOLLY` \| `ACTION.TOUCH_ZOOM` \| `CameraControls.ACTION.TOUCH_ROTATE` \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.NONE` | * | `touches.three` | `ACTION.TOUCH_DOLLY_TRUCK` \| `ACTION.TOUCH_DOLLY_OFFSET` \| `ACTION.TOUCH_DOLLY_ROTATE` \| `ACTION.TOUCH_ZOOM_TRUCK` \| `ACTION.TOUCH_ZOOM_OFFSET` \| `ACTION.TOUCH_ZOOM_ROTATE` \| `CameraControls.ACTION.TOUCH_ROTATE` \| `CameraControls.ACTION.TOUCH_TRUCK` \| `CameraControls.ACTION.TOUCH_OFFSET` \| `CameraControls.ACTION.NONE` | * * - \* is the default. * - The default of `touches.two` and `touches.three` is: * - `TOUCH_DOLLY_TRUCK` for Perspective camera. * - `TOUCH_ZOOM_TRUCK` for Orthographic camera, and can't set `TOUCH_DOLLY_TRUCK` and `TOUCH_DOLLY`. * @category Properties */ touches; /** * Force cancel user dragging. * @category Methods */ cancel = () => {}; /** * Still an experimental feature. * This could change at any time. * @category Methods */ lockPointer; /** * Still an experimental feature. * This could change at any time. * @category Methods */ unlockPointer; _enabled = true; _camera; _yAxisUpSpace; _yAxisUpSpaceInverse; _state = ACTION.NONE; _domElement; _viewport = null; _target; _targetEnd; _focalOffset; _focalOffsetEnd; _spherical; _sphericalEnd; _lastDistance; _zoom; _zoomEnd; _lastZoom; _cameraUp0; _target0; _position0; _zoom0; _focalOffset0; _dollyControlCoord; _changedDolly = 0; _changedZoom = 0; _nearPlaneCorners; _hasRested = true; _boundary; _boundaryEnclosesCamera = false; _needsUpdate = true; _updatedLastTime = false; _elementRect = new DOMRect(); _isDragging = false; _dragNeedsUpdate = true; _activePointers = []; _lockedPointer = null; _interactiveArea = new DOMRect(0, 0, 1, 1); _isUserControllingRotate = false; _isUserControllingDolly = false; _isUserControllingTruck = false; _isUserControllingOffset = false; _isUserControllingZoom = false; _lastDollyDirection = DOLLY_DIRECTION.NONE; _thetaVelocity = { value: 0 }; _phiVelocity = { value: 0 }; _radiusVelocity = { value: 0 }; _targetVelocity = new THREE.Vector3(); _focalOffsetVelocity = new THREE.Vector3(); _zoomVelocity = { value: 0 }; /** * @deprecated Use `cameraControls.mouseButtons.left = CameraControls.ACTION.SCREEN_PAN` instead. */ set verticalDragToForward(_) { console.warn("camera-controls: `verticalDragToForward` was removed. Use `mouseButtons.left = CameraControls.ACTION.SCREEN_PAN` instead."); } /** * Creates a `CameraControls` instance. * * Note: * You **must install** three.js before using camera-controls. see [#install](#install) * Not doing so will lead to runtime errors (`undefined` references to THREE). * * e.g. * ``` * CameraControls.install( { THREE } ); * const cameraControls = new CameraControls( camera, domElement ); * ``` * * @param camera A `THREE.PerspectiveCamera` or `THREE.OrthographicCamera` to be controlled. * @param domElement A `HTMLElement` for the draggable area, usually `renderer.domElement`. * @category Constructor */ constructor(camera, domElement) { super(); if (typeof THREE === "undefined") console.error("camera-controls: `THREE` is undefined. You must first run `CameraControls.install( { THREE: THREE } )`. Check the docs for further information."); this._camera = camera; this._yAxisUpSpace = new THREE.Quaternion().setFromUnitVectors(this._camera.up, _AXIS_Y); this._yAxisUpSpaceInverse = this._yAxisUpSpace.clone().invert(); this._state = ACTION.NONE; this._target = new THREE.Vector3(); this._targetEnd = this._target.clone(); this._focalOffset = new THREE.Vector3(); this._focalOffsetEnd = this._focalOffset.clone(); this._spherical = new THREE.Spherical().setFromVector3(_v3A.copy(this._camera.position).applyQuaternion(this._yAxisUpSpace)); this._sphericalEnd = this._spherical.clone(); this._lastDistance = this._spherical.radius; this._zoom = this._camera.zoom; this._zoomEnd = this._zoom; this._lastZoom = this._zoom; this._nearPlaneCorners = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; this._updateNearPlaneCorners(); this._boundary = new THREE.Box3(new THREE.Vector3(-Infinity, -Infinity, -Infinity), new THREE.Vector3(Infinity, Infinity, Infinity)); this._cameraUp0 = this._camera.up.clone(); this._target0 = this._target.clone(); this._position0 = this._camera.position.clone(); this._zoom0 = this._zoom; this._focalOffset0 = this._focalOffset.clone(); this._dollyControlCoord = new THREE.Vector2(); this.mouseButtons = { left: ACTION.ROTATE, middle: ACTION.DOLLY, right: ACTION.TRUCK, wheel: isPerspectiveCamera(this._camera) ? ACTION.DOLLY : isOrthographicCamera$1(this._camera) ? ACTION.ZOOM : ACTION.NONE }; this.touches = { one: ACTION.TOUCH_ROTATE, two: isPerspectiveCamera(this._camera) ? ACTION.TOUCH_DOLLY_TRUCK : isOrthographicCamera$1(this._camera) ? ACTION.TOUCH_ZOOM_TRUCK : ACTION.NONE, three: ACTION.TOUCH_TRUCK }; const dragStartPosition = new THREE.Vector2(); const lastDragPosition = new THREE.Vector2(); const dollyStart = new THREE.Vector2(); const onPointerDown = (event) => { if (!this._enabled || !this._domElement) return; if (this._interactiveArea.left !== 0 || this._interactiveArea.top !== 0 || this._interactiveArea.width !== 1 || this._interactiveArea.height !== 1) { const elRect = this._domElement.getBoundingClientRect(); const left = event.clientX / elRect.width; const top = event.clientY / elRect.height; if (left < this._interactiveArea.left || left > this._interactiveArea.right || top < this._interactiveArea.top || top > this._interactiveArea.bottom) return; } const mouseButton = event.pointerType !== "mouse" ? null : (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT ? MOUSE_BUTTON.LEFT : (event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE ? MOUSE_BUTTON.MIDDLE : (event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT ? MOUSE_BUTTON.RIGHT : null; if (mouseButton !== null) { const zombiePointer = this._findPointerByMouseButton(mouseButton); zombiePointer && this._disposePointer(zombiePointer); } if ((event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT && this._lockedPointer) return; const pointer = { pointerId: event.pointerId, clientX: event.clientX, clientY: event.clientY, deltaX: 0, deltaY: 0, mouseButton }; this._activePointers.push(pointer); this._domElement.ownerDocument.removeEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.removeEventListener("pointerup", onPointerUp); this._domElement.ownerDocument.addEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.addEventListener("pointerup", onPointerUp); this._isDragging = true; startDragging(event); }; const onPointerMove = (event) => { if (event.cancelable) event.preventDefault(); const pointerId = event.pointerId; const pointer = this._lockedPointer || this._findPointerById(pointerId); if (!pointer) return; pointer.clientX = event.clientX; pointer.clientY = event.clientY; pointer.deltaX = event.movementX; pointer.deltaY = event.movementY; this._state = 0; if (event.pointerType === "touch") switch (this._activePointers.length) { case 1: this._state = this.touches.one; break; case 2: this._state = this.touches.two; break; case 3: this._state = this.touches.three; break; } else { if (!this._isDragging && this._lockedPointer || this._isDragging && (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT) this._state = this._state | this.mouseButtons.left; if (this._isDragging && (event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE) this._state = this._state | this.mouseButtons.middle; if (this._isDragging && (event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT) this._state = this._state | this.mouseButtons.right; } dragging(); }; const onPointerUp = (event) => { const pointer = this._findPointerById(event.pointerId); if (pointer && pointer === this._lockedPointer) return; pointer && this._disposePointer(pointer); if (event.pointerType === "touch") switch (this._activePointers.length) { case 0: this._state = ACTION.NONE; break; case 1: this._state = this.touches.one; break; case 2: this._state = this.touches.two; break; case 3: this._state = this.touches.three; break; } else this._state = ACTION.NONE; endDragging(); }; let lastScrollTimeStamp = -1; const onMouseWheel = (event) => { if (!this._domElement) return; if (!this._enabled || this.mouseButtons.wheel === ACTION.NONE) return; if (this._interactiveArea.left !== 0 || this._interactiveArea.top !== 0 || this._interactiveArea.width !== 1 || this._interactiveArea.height !== 1) { const elRect = this._domElement.getBoundingClientRect(); const left = event.clientX / elRect.width; const top = event.clientY / elRect.height; if (left < this._interactiveArea.left || left > this._interactiveArea.right || top < this._interactiveArea.top || top > this._interactiveArea.bottom) return; } event.preventDefault(); if (this.dollyToCursor || this.mouseButtons.wheel === ACTION.ROTATE || this.mouseButtons.wheel === ACTION.TRUCK) { const now = performance.now(); if (lastScrollTimeStamp - now < 1e3) this._getClientRect(this._elementRect); lastScrollTimeStamp = now; } const deltaYFactor = isMac ? -1 : -3; const delta = event.deltaMode === 1 && !event.ctrlKey ? event.deltaY / deltaYFactor : event.deltaY / (deltaYFactor * 10); const x = this.dollyToCursor ? (event.clientX - this._elementRect.x) / this._elementRect.width * 2 - 1 : 0; const y = this.dollyToCursor ? (event.clientY - this._elementRect.y) / this._elementRect.height * -2 + 1 : 0; switch (event.ctrlKey ? ACTION.ZOOM : this.mouseButtons.wheel) { case ACTION.ROTATE: this._rotateInternal(event.deltaX, event.deltaY); this._isUserControllingRotate = true; break; case ACTION.TRUCK: this._truckInternal(event.deltaX, event.deltaY, false, false); this._isUserControllingTruck = true; break; case ACTION.SCREEN_PAN: this._truckInternal(event.deltaX, event.deltaY, false, true); this._isUserControllingTruck = true; break; case ACTION.OFFSET: this._truckInternal(event.deltaX, event.deltaY, true, false); this._isUserControllingOffset = true; break; case ACTION.DOLLY: this._dollyInternal(-delta, x, y); this._isUserControllingDolly = true; break; case ACTION.ZOOM: this._zoomInternal(-delta, x, y); this._isUserControllingZoom = true; break; } this.dispatchEvent({ type: "control" }); }; const onContextMenu = (event) => { if (!this._domElement || !this._enabled) return; if (this.mouseButtons.right === CameraControls$1.ACTION.NONE) { const pointerId = event instanceof PointerEvent ? event.pointerId : 0; const pointer = this._findPointerById(pointerId); pointer && this._disposePointer(pointer); this._domElement.ownerDocument.removeEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.removeEventListener("pointerup", onPointerUp); return; } event.preventDefault(); }; const startDragging = (event) => { if (!this._enabled) return; extractClientCoordFromEvent(this._activePointers, _v2); this._getClientRect(this._elementRect); dragStartPosition.copy(_v2); lastDragPosition.copy(_v2); if (this._activePointers.length >= 2) { const dx = _v2.x - this._activePointers[1].clientX; const dy = _v2.y - this._activePointers[1].clientY; const distance = Math.sqrt(dx * dx + dy * dy); dollyStart.set(0, distance); const x = (this._activePointers[0].clientX + this._activePointers[1].clientX) * .5; const y = (this._activePointers[0].clientY + this._activePointers[1].clientY) * .5; lastDragPosition.set(x, y); } this._state = 0; if (!event) { if (this._lockedPointer) this._state = this._state | this.mouseButtons.left; } else if ("pointerType" in event && event.pointerType === "touch") switch (this._activePointers.length) { case 1: this._state = this.touches.one; break; case 2: this._state = this.touches.two; break; case 3: this._state = this.touches.three; break; } else { if (!this._lockedPointer && (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT) this._state = this._state | this.mouseButtons.left; if ((event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE) this._state = this._state | this.mouseButtons.middle; if ((event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT) this._state = this._state | this.mouseButtons.right; } if ((this._state & ACTION.ROTATE) === ACTION.ROTATE || (this._state & ACTION.TOUCH_ROTATE) === ACTION.TOUCH_ROTATE || (this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) { this._sphericalEnd.theta = this._spherical.theta; this._sphericalEnd.phi = this._spherical.phi; this._thetaVelocity.value = 0; this._phiVelocity.value = 0; } if ((this._state & ACTION.TRUCK) === ACTION.TRUCK || (this._state & ACTION.SCREEN_PAN) === ACTION.SCREEN_PAN || (this._state & ACTION.TOUCH_TRUCK) === ACTION.TOUCH_TRUCK || (this._state & ACTION.TOUCH_SCREEN_PAN) === ACTION.TOUCH_SCREEN_PAN || (this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (this._state & ACTION.TOUCH_DOLLY_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN || (this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK || (this._state & ACTION.TOUCH_ZOOM_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN) { this._targetEnd.copy(this._target); this._targetVelocity.set(0, 0, 0); } if ((this._state & ACTION.DOLLY) === ACTION.DOLLY || (this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (this._state & ACTION.TOUCH_DOLLY_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN || (this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE) { this._sphericalEnd.radius = this._spherical.radius; this._radiusVelocity.value = 0; } if ((this._state & ACTION.ZOOM) === ACTION.ZOOM || (this._state & ACTION.TOUCH_ZOOM) === ACTION.TOUCH_ZOOM || (this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK || (this._state & ACTION.TOUCH_ZOOM_SCREEN_PAN) === ACTION.TOUCH_ZOOM_SCREEN_PAN || (this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET || (this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) { this._zoomEnd = this._zoom; this._zoomVelocity.value = 0; } if ((this._state & ACTION.OFFSET) === ACTION.OFFSET || (this._state & ACTION.TOUCH_OFFSET) === ACTION.TOUCH_OFFSET || (this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET) { this._focalOffsetEnd.copy(this._focalOffset); this._focalOffsetVelocity.set(0, 0, 0); } this.dispatchEvent({ type: "controlstart" }); }; const dragging = () => { if (!this._enabled || !this._dragNeedsUpdate) return; this._dragNeedsUpdate = false; extractClientCoordFromEvent(this._activePointers, _v2); const lockedPointer = this._domElement && this._domElement.ownerDocument.pointerLockElement === this._domElement ? this._lockedPointer || this._activePointers[0] : null; const deltaX = lockedPointer ? -lockedPointer.deltaX : lastDragPosition.x - _v2.x; const deltaY = lockedPointer ? -lockedPointer.deltaY : lastDragPosition.y - _v2.y; lastDragPosition.copy(_v2); if ((this._state & ACTION.ROTATE) === ACTION.ROTATE || (this._state & ACTION.TOUCH_ROTATE) === ACTION.TOUCH_ROTATE || (this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) { this._rotateInternal(deltaX, deltaY); this._isUserControllingRotate = true; } if ((this._state & ACTION.DOLLY) === ACTION.DOLLY || (this._state & ACTION.ZOOM) === ACTION.ZOOM) { const dollyX = this.dollyToCursor ? (dragStartPosition.x - this._elementRect.x) / this._elementRect.width * 2 - 1 : 0; const dollyY = this.dollyToCursor ? (dragStartPosition.y - this._elementRect.y) / this._elementRect.height * -2 + 1 : 0; const dollyDirection = this.dollyDragInverted ? -1 : 1; if ((this._state & ACTION.DOLLY) === ACTION.DOLLY) { this._dollyInternal(dollyDirection * deltaY * TOUCH_DOLLY_FACTOR, dollyX, dollyY); this._isUserControllingDolly = true; } else { this._zoomInternal(dollyDirection * deltaY * TOUCH_DOLLY_FACTOR, dollyX, dollyY); this._isUserControllingZoom = true; } } if ((this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (this._state & ACTION.TOUCH_ZOOM) === ACTION.TOUCH_ZOOM || (this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK || (this._state & ACTION.TOUCH_DOLLY_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN || (this._state & ACTION.TOUCH_ZOOM_SCREEN_PAN) === ACTION.TOUCH_ZOOM_SCREEN_PAN || (this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET || (this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) { const dx = _v2.x - this._activePointers[1].clientX; const dy = _v2.y - this._activePointers[1].clientY; const distance = Math.sqrt(dx * dx + dy * dy); const dollyDelta = dollyStart.y - distance; dollyStart.set(0, distance); const dollyX = this.dollyToCursor ? (lastDragPosition.x - this._elementRect.x) / this._elementRect.width * 2 - 1 : 0; const dollyY = this.dollyToCursor ? (lastDragPosition.y - this._elementRect.y) / this._elementRect.height * -2 + 1 : 0; if ((this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (this._state & ACTION.TOUCH_DOLLY_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN || (this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET) { this._dollyInternal(dollyDelta * TOUCH_DOLLY_FACTOR, dollyX, dollyY); this._isUserControllingDolly = true; } else { this._zoomInternal(dollyDelta * TOUCH_DOLLY_FACTOR, dollyX, dollyY); this._isUserControllingZoom = true; } } if ((this._state & ACTION.TRUCK) === ACTION.TRUCK || (this._state & ACTION.TOUCH_TRUCK) === ACTION.TOUCH_TRUCK || (this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK) { this._truckInternal(deltaX, deltaY, false, false); this._isUserControllingTruck = true; } if ((this._state & ACTION.SCREEN_PAN) === ACTION.SCREEN_PAN || (this._state & ACTION.TOUCH_SCREEN_PAN) === ACTION.TOUCH_SCREEN_PAN || (this._state & ACTION.TOUCH_DOLLY_SCREEN_PAN) === ACTION.TOUCH_DOLLY_SCREEN_PAN || (this._state & ACTION.TOUCH_ZOOM_SCREEN_PAN) === ACTION.TOUCH_ZOOM_SCREEN_PAN) { this._truckInternal(deltaX, deltaY, false, true); this._isUserControllingTruck = true; } if ((this._state & ACTION.OFFSET) === ACTION.OFFSET || (this._state & ACTION.TOUCH_OFFSET) === ACTION.TOUCH_OFFSET || (this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET) { this._truckInternal(deltaX, deltaY, true, false); this._isUserControllingOffset = true; } this.dispatchEvent({ type: "control" }); }; const endDragging = () => { extractClientCoordFromEvent(this._activePointers, _v2); lastDragPosition.copy(_v2); this._dragNeedsUpdate = false; if (this._activePointers.length === 0 || this._activePointers.length === 1 && this._activePointers[0] === this._lockedPointer) this._isDragging = false; if (this._activePointers.length === 0 && this._domElement) { this._domElement.ownerDocument.removeEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.removeEventListener("pointerup", onPointerUp); this.dispatchEvent({ type: "controlend" }); } }; this.lockPointer = () => { if (!this._enabled || !this._domElement) return; this.cancel(); this._lockedPointer = { pointerId: -1, clientX: 0, clientY: 0, deltaX: 0, deltaY: 0, mouseButton: null }; this._activePointers.push(this._lockedPointer); this._domElement.ownerDocument.removeEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.removeEventListener("pointerup", onPointerUp); this._domElement.requestPointerLock(); this._domElement.ownerDocument.addEventListener("pointerlockchange", onPointerLockChange); this._domElement.ownerDocument.addEventListener("pointerlockerror", onPointerLockError); this._domElement.ownerDocument.addEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.addEventListener("pointerup", onPointerUp); startDragging(); }; this.unlockPointer = () => { if (this._lockedPointer !== null) { this._disposePointer(this._lockedPointer); this._lockedPointer = null; } this._domElement?.ownerDocument.exitPointerLock(); this._domElement?.ownerDocument.removeEventListener("pointerlockchange", onPointerLockChange); this._domElement?.ownerDocument.removeEventListener("pointerlockerror", onPointerLockError); this.cancel(); }; const onPointerLockChange = () => { if (!(this._domElement && this._domElement.ownerDocument.pointerLockElement === this._domElement)) this.unlockPointer(); }; const onPointerLockError = () => { this.unlockPointer(); }; this._addAllEventListeners = (domElement) => { this._domElement = domElement; this._domElement.style.touchAction = "none"; this._domElement.style.userSelect = "none"; this._domElement.style.webkitUserSelect = "none"; this._domElement.addEventListener("pointerdown", onPointerDown); this._domElement.addEventListener("pointercancel", onPointerUp); this._domElement.addEventListener("wheel", onMouseWheel, { passive: false }); this._domElement.addEventListener("contextmenu", onContextMenu); }; this._removeAllEventListeners = () => { if (!this._domElement) return; this._domElement.style.touchAction = ""; this._domElement.style.userSelect = ""; this._domElement.style.webkitUserSelect = ""; this._domElement.removeEventListener("pointerdown", onPointerDown); this._domElement.removeEventListener("pointercancel", onPointerUp); this._domElement.removeEventListener("wheel", onMouseWheel, { passive: false }); this._domElement.removeEventListener("contextmenu", onContextMenu); this._domElement.ownerDocument.removeEventListener("pointermove", onPointerMove, { passive: false }); this._domElement.ownerDocument.removeEventListener("pointerup", onPointerUp); this._domElement.ownerDocument.removeEventListener("pointerlockchange", onPointerLockChange); this._domElement.ownerDocument.removeEventListener("pointerlockerror", onPointerLockError); }; this.cancel = () => { if (this._state === ACTION.NONE) return; this._state = ACTION.NONE; this._activePointers.length = 0; endDragging(); }; if (domElement) this.connect(domElement); this.update(0); } /** * The camera to be controlled * @category Properties */ get camera() { return this._camera; } set camera(camera) { this._camera = camera; this.updateCameraUp(); this._camera.updateProjectionMatrix(); this._updateNearPlaneCorners(); this._needsUpdate = true; } /** * Whether or not the controls are enabled. * `false` to disable user dragging/touch-move, but all methods works. * @category Properties */ get enabled() { return this._enabled; } set enabled(enabled) { this._enabled = enabled; if (!this._domElement) return; if (enabled) { this._domElement.style.touchAction = "none"; this._domElement.style.userSelect = "none"; this._domElement.style.webkitUserSelect = "none"; } else { this.cancel(); this._domElement.style.touchAction = ""; this._domElement.style.userSelect = ""; this._domElement.style.webkitUserSelect = ""; } } /** * Returns `true` if the controls are active updating. * readonly value. * @category Properties */ get active() { return !this._hasRested; } /** * Getter for the current `ACTION`. * readonly value. * @category Properties */ get currentAction() { return this._state; } /** * get/set Current distance. * @category Properties */ get distance() { return this._spherical.radius; } set distance(distance) { if (this._spherical.radius === distance && this._sphericalEnd.radius === distance) return; this._spherical.radius = distance; this._sphericalEnd.radius = distance; this._needsUpdate = true; } /** * get/set the azimuth angle (horizontal) in radians. * Every 360 degrees turn is added to `.azimuthAngle` value, which is accumulative. * @category Properties */ get azimuthAngle() { return this._spherical.theta; } set azimuthAngle(azimuthAngle) { if (this._spherical.theta === azimuthAngle && this._sphericalEnd.theta === azimuthAngle) return; this._spherical.theta = azimuthAngle; this._sphericalEnd.theta = azimuthAngle; this._needsUpdate = true; } /** * get/set the polar angle (vertical) in radians. * @category Properties */ get polarAngle() { return this._spherical.phi; } set polarAngle(polarAngle) { if (this._spherical.phi === polarAngle && this._sphericalEnd.phi === polarAngle) return; this._spherical.phi = polarAngle; this._sphericalEnd.phi = polarAngle; this._needsUpdate = true; } /** * Whether camera position should be enclosed in the boundary or not. * @category Properties */ get boundaryEnclosesCamera() { return this._boundaryEnclosesCamera; } set boundaryEnclosesCamera(boundaryEnclosesCamera) { this._boundaryEnclosesCamera = boundaryEnclosesCamera; this._needsUpdate = true; } /** * Set drag-start, touches and wheel enable area in the domElement. * each values are between `0` and `1` inclusive, where `0` is left/top and `1` is right/bottom of the screen. * e.g. `{ x: 0, y: 0, width: 1, height: 1 }` for entire area. * @category Properties */ set interactiveArea(interactiveArea) { this._interactiveArea.width = clamp(interactiveArea.width, 0, 1); this._interactiveArea.height = clamp(interactiveArea.height, 0, 1); this._interactiveArea.x = clamp(interactiveArea.x, 0, 1 - this._interactiveArea.width); this._interactiveArea.y = clamp(interactiveArea.y, 0, 1 - this._interactiveArea.height); } /** * Adds the specified event listener. * Applicable event types (which is `K`) are: * | Event name | Timing | * | ------------------- | ------ | * | `'controlstart'` | When the user starts to control the camera via mouse / touches. ¹ | * | `'control'` | When the user controls the camera (dragging). | * | `'controlend'` | When the user ends to control the camera. ¹ | * | `'transitionstart'` | When any kind of transition starts, either user control or using a method with `enableTransition = true` | * | `'update'` | When the camera position is updated. | * | `'wake'` | When the camera starts moving. | * | `'rest'` | When the camera movement is below `.restThreshold` ². | * | `'sleep'` | When the camera end moving. | * * 1. `mouseButtons.wheel` (Mouse wheel control) does not emit `'controlstart'` and `'controlend'`. `mouseButtons.wheel` uses scroll-event internally, and scroll-event happens intermittently. That means "start" and "end" cannot be detected. * 2. Due to damping, `sleep` will usually fire a few seconds after the camera _appears_ to have stopped moving. If you want to do something (e.g. enable UI, perform another transition) at the point when the camera has stopped, you probably want the `rest` event. This can be fine tuned using the `.restThreshold` parameter. See the [Rest and Sleep Example](https://yomotsu.github.io/camera-controls/examples/rest-and-sleep.html). * * e.g. * ``` * cameraControl.addEventListener( 'controlstart', myCallbackFunction ); * ``` * @param type event name * @param listener handler function * @category Methods */ addEventListener(type, listener) { super.addEventListener(type, listener); } /** * Removes the specified event listener * e.g. * ``` * cameraControl.addEventListener( 'controlstart', myCallbackFunction ); * ``` * @param type event name * @param listener handler function * @category Methods */ removeEventListener(type, listener) { super.removeEventListener(type, listener); } /** * Rotate azimuthal angle(horizontal) and polar angle(vertical). * Every value is added to the current value. * @param azimuthAngle Azimuth rotate angle. In radian. * @param polarAngle Polar rotate angle. In radian. * @param enableTransition Whether to move smoothly or immediately * @category Methods */ rotate(azimuthAngle, polarAngle, enableTransition = false) { return this.rotateTo(this._sphericalEnd.theta + azimuthAngle, this._sphericalEnd.phi + polarAngle, enableTransition); } /** * Rotate azimuthal angle(horizontal) to the given angle and keep the same polar angle(vertical) target. * * e.g. * ``` * cameraControls.rotateAzimuthTo( 30 * THREE.MathUtils.DEG2RAD, true ); * ``` * @param azimuthAngle Azimuth rotate angle. In radian. * @param enableTransition Whether to move smoothly or immediately * @category Methods */ rotateAzimuthTo(azimuthAngle, enableTransition = false) { return this.rotateTo(azimuthAngle, this._sphericalEnd.phi, enableTransition); } /** * Rotate polar angle(vertical) to the given angle and keep the same azimuthal angle(horizontal) target. * * e.g. * ``` * cameraControls.rotatePolarTo( 30 * THREE.MathUtils.DEG2RAD, true ); * ``` * @param polarAngle Polar rotate angle. In radian. * @param enableTransition Whether to move smoothly or immediately * @category Methods */ rotatePolarTo(polarAngle, enableTransition = false) { return this.rotateTo(this._sphericalEnd.theta, polarAngle, enableTransition); } /** * Rotate azimuthal angle(horizontal) and polar angle(vertical) to the given angle. * Camera view will rotate over the orbit pivot absolutely: * * azimuthAngle * ``` * 0º * \ * 90º -----+----- -90º * \ * 180º * ``` * | direction | angle | * | --------- | ---------------------- | * | front | 0º | * | left | 90º (`Math.PI / 2`) | * | right | -90º (`- Math.PI / 2`) | * | back | 180º (`Math.PI`) | * * polarAngle * ``` * 180º * | * 90º * | * 0º * ``` * | direction | angle | * | -------------------- | ---------------------- | * | top/sky | 180º (`Math.PI`) | * | horizontal from view | 90º (`Math.PI / 2`) | * | bottom/floor | 0º | * * @param azimuthAngle Azimuth rotate angle to. In radian. * @param polarAngle Polar rotate angle to. In radian. * @param enableTransition Whether to move smoothly or immediately * @category Methods */ rotateTo(azimuthAngle, polarAngle, enableTransition = false) { this._isUserControllingRotate = false; const theta = clamp(azimuthAngle, this.minAzimuthAngle, this.maxAzimuthAngle); const phi = clamp(polarAngle, this.minPolarAngle, this.maxPolarAngle); this._sphericalEnd.theta = theta; this._sphericalEnd.phi = phi; this._sphericalEnd.makeSafe(); this._needsUpdate = true; if (!enableTransition) { this._spherical.theta = this._sphericalEnd.theta; this._spherical.phi = this._sphericalEnd.phi; } const resolveImmediately = !enableTransition || approxEquals(this._spherical.theta, this._sphericalEnd.theta, this.restThreshold) && approxEquals(this._spherical.phi, this._sphericalEnd.phi, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Dolly in/out camera position. * @param distance Distance of dollyIn. Negative number for dollyOut. * @param enableTransition Whether to move smoothly or immediately. * @category Methods */ dolly(distance, enableTransition = false) { return this.dollyTo(this._sphericalEnd.radius - distance, enableTransition); } /** * Dolly in/out camera position to given distance. * @param distance Distance of dolly. * @param enableTransition Whether to move smoothly or immediately. * @category Methods */ dollyTo(distance, enableTransition = false) { this._isUserControllingDolly = false; this._lastDollyDirection = DOLLY_DIRECTION.NONE; this._changedDolly = 0; return this._dollyToNoClamp(clamp(distance, this.minDistance, this.maxDistance), enableTransition); } _dollyToNoClamp(distance, enableTransition = false) { const lastRadius = this._sphericalEnd.radius; if (this.colliderMeshes.length >= 1) { const maxDistanceByCollisionTest = this._collisionTest(); const isCollided = approxEquals(maxDistanceByCollisionTest, this._spherical.radius); if (!(lastRadius > distance) && isCollided) return Promise.resolve(); this._sphericalEnd.radius = Math.min(distance, maxDistanceByCollisionTest); } else this._sphericalEnd.radius = distance; this._needsUpdate = true; if (!enableTransition) this._spherical.radius = this._sphericalEnd.radius; const resolveImmediately = !enableTransition || approxEquals(this._spherical.radius, this._sphericalEnd.radius, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Dolly in, but does not change the distance between the target and the camera, and moves the target position instead. * Specify a negative value for dolly out. * @param distance Distance of dolly. * @param enableTransition Whether to move smoothly or immediately. * @category Methods */ dollyInFixed(distance, enableTransition = false) { this._targetEnd.add(this._getCameraDirection(_cameraDirection).multiplyScalar(distance)); if (!enableTransition) this._target.copy(this._targetEnd); const resolveImmediately = !enableTransition || approxEquals(this._target.x, this._targetEnd.x, this.restThreshold) && approxEquals(this._target.y, this._targetEnd.y, this.restThreshold) && approxEquals(this._target.z, this._targetEnd.z, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Zoom in/out camera. The value is added to camera zoom. * Limits set with `.minZoom` and `.maxZoom` * @param zoomStep zoom scale * @param enableTransition Whether to move smoothly or immediately * @category Methods */ zoom(zoomStep, enableTransition = false) { return this.zoomTo(this._zoomEnd + zoomStep, enableTransition); } /** * Zoom in/out camera to given scale. The value overwrites camera zoom. * Limits set with .minZoom and .maxZoom * @param zoom * @param enableTransition * @category Methods */ zoomTo(zoom, enableTransition = false) { this._isUserControllingZoom = false; this._zoomEnd = clamp(zoom, this.minZoom, this.maxZoom); this._needsUpdate = true; if (!enableTransition) this._zoom = this._zoomEnd; const resolveImmediately = !enableTransition || approxEquals(this._zoom, this._zoomEnd, this.restThreshold); this._changedZoom = 0; return this._createOnRestPromise(resolveImmediately); } /** * @deprecated `pan()` has been renamed to `truck()` * @category Methods */ pan(x, y, enableTransition = false) { console.warn("`pan` has been renamed to `truck`"); return this.truck(x, y, enableTransition); } /** * Truck and pedestal camera using current azimuthal angle * @param x Horizontal translate amount * @param y Vertical translate amount * @param enableTransition Whether to move smoothly or immediately * @category Methods */ truck(x, y, enableTransition = false) { this._camera.updateMatrix(); _xColumn.setFromMatrixColumn(this._camera.matrix, 0); _yColumn.setFromMatrixColumn(this._camera.matrix, 1); _xColumn.multiplyScalar(x); _yColumn.multiplyScalar(-y); const offset = _v3A.copy(_xColumn).add(_yColumn); const to = _v3B.copy(this._targetEnd).add(offset); return this.moveTo(to.x, to.y, to.z, enableTransition); } /** * Move forward / backward. * @param distance Amount to move forward / backward. Negative value to move backward * @param enableTransition Whether to move smoothly or immediately * @category Methods */ forward(distance, enableTransition = false) { _v3A.setFromMatrixColumn(this._camera.matrix, 0); _v3A.crossVectors(this._camera.up, _v3A); _v3A.multiplyScalar(distance); const to = _v3B.copy(this._targetEnd).add(_v3A); return this.moveTo(to.x, to.y, to.z, enableTransition); } /** * Move up / down. * @param height Amount to move up / down. Negative value to move down * @param enableTransition Whether to move smoothly or immediately * @category Methods */ elevate(height, enableTransition = false) { _v3A.copy(this._camera.up).multiplyScalar(height); return this.moveTo(this._targetEnd.x + _v3A.x, this._targetEnd.y + _v3A.y, this._targetEnd.z + _v3A.z, enableTransition); } /** * Move target position to given point. * @param x x coord to move center position * @param y y coord to move center position * @param z z coord to move center position * @param enableTransition Whether to move smoothly or immediately * @category Methods */ moveTo(x, y, z, enableTransition = false) { this._isUserControllingTruck = false; const offset = _v3A.set(x, y, z).sub(this._targetEnd); this._encloseToBoundary(this._targetEnd, offset, this.boundaryFriction); this._needsUpdate = true; if (!enableTransition) this._target.copy(this._targetEnd); const resolveImmediately = !enableTransition || approxEquals(this._target.x, this._targetEnd.x, this.restThreshold) && approxEquals(this._target.y, this._targetEnd.y, this.restThreshold) && approxEquals(this._target.z, this._targetEnd.z, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Look in the given point direction. * @param x point x. * @param y point y. * @param z point z. * @param enableTransition Whether to move smoothly or immediately. * @returns Transition end promise * @category Methods */ lookInDirectionOf(x, y, z, enableTransition = false) { const position = _v3A.set(x, y, z).sub(this._targetEnd).normalize().multiplyScalar(-this._sphericalEnd.radius).add(this._targetEnd); return this.setPosition(position.x, position.y, position.z, enableTransition); } /** * Fit the viewport to the box or the bounding box of the object, using the nearest axis. paddings are in unit. * set `cover: true` to fill enter screen. * e.g. * ``` * cameraControls.fitToBox( myMesh ); * ``` * @param box3OrObject Axis aligned bounding box to fit the view. * @param enableTransition Whether to move smoothly or immediately. * @param options | `` { cover: boolean, paddingTop: number, paddingLeft: number, paddingBottom: number, paddingRight: number } * @returns Transition end promise * @category Methods */ fitToBox(box3OrObject, enableTransition, { cover = false, paddingLeft = 0, paddingRight = 0, paddingBottom = 0, paddingTop = 0 } = {}) { const promises = []; const aabb = box3OrObject.isBox3 ? _box3A.copy(box3OrObject) : _box3A.setFromObject(box3OrObject); if (aabb.isEmpty()) { console.warn("camera-controls: fitTo() cannot be used with an empty box. Aborting"); Promise.resolve(); } const theta = roundToStep(this._sphericalEnd.theta, PI_HALF); const phi = roundToStep(this._sphericalEnd.phi, PI_HALF); promises.push(this.rotateTo(theta, phi, enableTransition)); const normal = _v3A.setFromSpherical(this._sphericalEnd).normalize(); const rotation = _quaternionA.setFromUnitVectors(normal, _AXIS_Z); const viewFromPolar = approxEquals(Math.abs(normal.y), 1); if (viewFromPolar) rotation.multiply(_quaternionB.setFromAxisAngle(_AXIS_Y, theta)); rotation.multiply(this._yAxisUpSpaceInverse); const bb = _box3B.makeEmpty(); _v3B.copy(aabb.min).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.min).setX(aabb.max.x).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.min).setY(aabb.max.y).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.max).setZ(aabb.min.z).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.min).setZ(aabb.max.z).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.max).setY(aabb.min.y).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.max).setX(aabb.min.x).applyQuaternion(rotation); bb.expandByPoint(_v3B); _v3B.copy(aabb.max).applyQuaternion(rotation); bb.expandByPoint(_v3B); bb.min.x -= paddingLeft; bb.min.y -= paddingBottom; bb.max.x += paddingRight; bb.max.y += paddingTop; rotation.setFromUnitVectors(_AXIS_Z, normal); if (viewFromPolar) rotation.premultiply(_quaternionB.invert()); rotation.premultiply(this._yAxisUpSpace); const bbSize = bb.getSize(_v3A); const center = bb.getCenter(_v3B).applyQuaternion(rotation); if (isPerspectiveCamera(this._camera)) { const distance = this.getDistanceToFitBox(bbSize.x, bbSize.y, bbSize.z, cover); promises.push(this.moveTo(center.x, center.y, center.z, enableTransition)); promises.push(this.dollyTo(distance, enableTransition)); promises.push(this.setFocalOffset(0, 0, 0, enableTransition)); } else if (isOrthographicCamera$1(this._camera)) { const camera = this._camera; const width = camera.right - camera.left; const height = camera.top - camera.bottom; const zoom = cover ? Math.max(width / bbSize.x, height / bbSize.y) : Math.min(width / bbSize.x, height / bbSize.y); promises.push(this.moveTo(center.x, center.y, center.z, enableTransition)); promises.push(this.zoomTo(zoom, enableTransition)); promises.push(this.setFocalOffset(0, 0, 0, enableTransition)); } return Promise.all(promises); } /** * Fit the viewport to the sphere or the bounding sphere of the object. * @param sphereOrMesh * @param enableTransition * @category Methods */ fitToSphere(sphereOrMesh, enableTransition) { const promises = []; const boundingSphere = "isObject3D" in sphereOrMesh ? CameraControls$1.createBoundingSphere(sphereOrMesh, _sphere$2) : _sphere$2.copy(sphereOrMesh); promises.push(this.moveTo(boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z, enableTransition)); if (isPerspectiveCamera(this._camera)) { const distanceToFit = this.getDistanceToFitSphere(boundingSphere.radius); promises.push(this.dollyTo(distanceToFit, enableTransition)); } else if (isOrthographicCamera$1(this._camera)) { const width = this._camera.right - this._camera.left; const height = this._camera.top - this._camera.bottom; const diameter = 2 * boundingSphere.radius; const zoom = Math.min(width / diameter, height / diameter); promises.push(this.zoomTo(zoom, enableTransition)); } promises.push(this.setFocalOffset(0, 0, 0, enableTransition)); return Promise.all(promises); } /** * Look at the `target` from the `position`. * @param positionX * @param positionY * @param positionZ * @param targetX * @param targetY * @param targetZ * @param enableTransition * @category Methods */ setLookAt(positionX, positionY, positionZ, targetX, targetY, targetZ, enableTransition = false) { this._isUserControllingRotate = false; this._isUserControllingDolly = false; this._isUserControllingTruck = false; this._lastDollyDirection = DOLLY_DIRECTION.NONE; this._changedDolly = 0; const target = _v3B.set(targetX, targetY, targetZ); const position = _v3A.set(positionX, positionY, positionZ); this._targetEnd.copy(target); this._sphericalEnd.setFromVector3(position.sub(target).applyQuaternion(this._yAxisUpSpace)); this._needsUpdate = true; if (!enableTransition) { this._target.copy(this._targetEnd); this._spherical.copy(this._sphericalEnd); } const resolveImmediately = !enableTransition || approxEquals(this._target.x, this._targetEnd.x, this.restThreshold) && approxEquals(this._target.y, this._targetEnd.y, this.restThreshold) && approxEquals(this._target.z, this._targetEnd.z, this.restThreshold) && approxEquals(this._spherical.theta, this._sphericalEnd.theta, this.restThreshold) && approxEquals(this._spherical.phi, this._sphericalEnd.phi, this.restThreshold) && approxEquals(this._spherical.radius, this._sphericalEnd.radius, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Interpolates between two states. * @param stateA * @param stateB * @param t * @param enableTransition * @category Methods */ lerp(stateA, stateB, t, enableTransition = false) { this._isUserControllingRotate = false; this._isUserControllingDolly = false; this._isUserControllingTruck = false; this._lastDollyDirection = DOLLY_DIRECTION.NONE; this._changedDolly = 0; const targetA = _v3A.set(...stateA.target); if ("spherical" in stateA) _sphericalA.set(...stateA.spherical); else { const positionA = _v3B.set(...stateA.position); _sphericalA.setFromVector3(positionA.sub(targetA).applyQuaternion(this._yAxisUpSpace)); } const targetB = _v3C.set(...stateB.target); if ("spherical" in stateB) _sphericalB.set(...stateB.spherical); else { const positionB = _v3B.set(...stateB.position); _sphericalB.setFromVector3(positionB.sub(targetB).applyQuaternion(this._yAxisUpSpace)); } this._targetEnd.copy(targetA.lerp(targetB, t)); const deltaTheta = _sphericalB.theta - _sphericalA.theta; const deltaPhi = _sphericalB.phi - _sphericalA.phi; const deltaRadius = _sphericalB.radius - _sphericalA.radius; this._sphericalEnd.set(_sphericalA.radius + deltaRadius * t, _sphericalA.phi + deltaPhi * t, _sphericalA.theta + deltaTheta * t); this._needsUpdate = true; if (!enableTransition) { this._target.copy(this._targetEnd); this._spherical.copy(this._sphericalEnd); } const resolveImmediately = !enableTransition || approxEquals(this._target.x, this._targetEnd.x, this.restThreshold) && approxEquals(this._target.y, this._targetEnd.y, this.restThreshold) && approxEquals(this._target.z, this._targetEnd.z, this.restThreshold) && approxEquals(this._spherical.theta, this._sphericalEnd.theta, this.restThreshold) && approxEquals(this._spherical.phi, this._sphericalEnd.phi, this.restThreshold) && approxEquals(this._spherical.radius, this._sphericalEnd.radius, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Similar to setLookAt, but it interpolates between two states. * @param positionAX * @param positionAY * @param positionAZ * @param targetAX * @param targetAY * @param targetAZ * @param positionBX * @param positionBY * @param positionBZ * @param targetBX * @param targetBY * @param targetBZ * @param t * @param enableTransition * @category Methods */ lerpLookAt(positionAX, positionAY, positionAZ, targetAX, targetAY, targetAZ, positionBX, positionBY, positionBZ, targetBX, targetBY, targetBZ, t, enableTransition = false) { return this.lerp({ position: [ positionAX, positionAY, positionAZ ], target: [ targetAX, targetAY, targetAZ ] }, { position: [ positionBX, positionBY, positionBZ ], target: [ targetBX, targetBY, targetBZ ] }, t, enableTransition); } /** * Set angle and distance by given position. * An alias of `setLookAt()`, without target change. Thus keep gazing at the current target * @param positionX * @param positionY * @param positionZ * @param enableTransition * @category Methods */ setPosition(positionX, positionY, positionZ, enableTransition = false) { return this.setLookAt(positionX, positionY, positionZ, this._targetEnd.x, this._targetEnd.y, this._targetEnd.z, enableTransition); } /** * Set the target position where gaze at. * An alias of `setLookAt()`, without position change. Thus keep the same position. * @param targetX * @param targetY * @param targetZ * @param enableTransition * @category Methods */ setTarget(targetX, targetY, targetZ, enableTransition = false) { const pos = this.getPosition(_v3A); const promise = this.setLookAt(pos.x, pos.y, pos.z, targetX, targetY, targetZ, enableTransition); this._sphericalEnd.phi = clamp(this._sphericalEnd.phi, this.minPolarAngle, this.maxPolarAngle); return promise; } /** * Set focal offset using the screen parallel coordinates. z doesn't affect in Orthographic as with Dolly. * @param x * @param y * @param z * @param enableTransition * @category Methods */ setFocalOffset(x, y, z, enableTransition = false) { this._isUserControllingOffset = false; this._focalOffsetEnd.set(x, y, z); this._needsUpdate = true; if (!enableTransition) this._focalOffset.copy(this._focalOffsetEnd); const resolveImmediately = !enableTransition || approxEquals(this._focalOffset.x, this._focalOffsetEnd.x, this.restThreshold) && approxEquals(this._focalOffset.y, this._focalOffsetEnd.y, this.restThreshold) && approxEquals(this._focalOffset.z, this._focalOffsetEnd.z, this.restThreshold); return this._createOnRestPromise(resolveImmediately); } /** * Set orbit point without moving the camera. * SHOULD NOT RUN DURING ANIMATIONS. `setOrbitPoint()` will immediately fix the positions. * @param targetX * @param targetY * @param targetZ * @category Methods */ setOrbitPoint(targetX, targetY, targetZ) { this._camera.updateMatrixWorld(); _xColumn.setFromMatrixColumn(this._camera.matrixWorldInverse, 0); _yColumn.setFromMatrixColumn(this._camera.matrixWorldInverse, 1); _zColumn.setFromMatrixColumn(this._camera.matrixWorldInverse, 2); const position = _v3A.set(targetX, targetY, targetZ); const distance = position.distanceTo(this._camera.position); const cameraToPoint = position.sub(this._camera.position); _xColumn.multiplyScalar(cameraToPoint.x); _yColumn.multiplyScalar(cameraToPoint.y); _zColumn.multiplyScalar(cameraToPoint.z); _v3A.copy(_xColumn).add(_yColumn).add(_zColumn); _v3A.z = _v3A.z + distance; this.dollyTo(distance, false); this.setFocalOffset(-_v3A.x, _v3A.y, -_v3A.z, false); this.moveTo(targetX, targetY, targetZ, false); } /** * Set the boundary box that encloses the target of the camera. box3 is in THREE.Box3 * @param box3 * @category Methods */ setBoundary(box3) { if (!box3) { this._boundary.min.set(-Infinity, -Infinity, -Infinity); this._boundary.max.set(Infinity, Infinity, Infinity); this._needsUpdate = true; return; } this._boundary.copy(box3); this._boundary.clampPoint(this._targetEnd, this._targetEnd); this._needsUpdate = true; } /** * Set (or unset) the current viewport. * Set this when you want to use renderer viewport and .dollyToCursor feature at the same time. * @param viewportOrX * @param y * @param width * @param height * @category Methods */ setViewport(viewportOrX, y, width, height) { if (viewportOrX === null) { this._viewport = null; return; } this._viewport = this._viewport || new THREE.Vector4(); if (typeof viewportOrX === "number") this._viewport.set(viewportOrX, y, width, height); else this._viewport.copy(viewportOrX); } /** * Calculate the distance to fit the box. * @param width box width * @param height box height * @param depth box depth * @returns distance * @category Methods */ getDistanceToFitBox(width, height, depth, cover = false) { if (notSupportedInOrthographicCamera(this._camera, "getDistanceToFitBox")) return this._spherical.radius; const boundingRectAspect = width / height; const fov = this._camera.getEffectiveFOV() * DEG2RAD; const aspect = this._camera.aspect; return ((cover ? boundingRectAspect > aspect : boundingRectAspect < aspect) ? height : width / aspect) * .5 / Math.tan(fov * .5) + depth * .5; } /** * Calculate the distance to fit the sphere. * @param radius sphere radius * @returns distance * @category Methods */ getDistanceToFitSphere(radius) { if (notSupportedInOrthographicCamera(this._camera, "getDistanceToFitSphere")) return this._spherical.radius; const vFOV = this._camera.getEffectiveFOV() * DEG2RAD; const hFOV = Math.atan(Math.tan(vFOV * .5) * this._camera.aspect) * 2; const fov = 1 < this._camera.aspect ? vFOV : hFOV; return radius / Math.sin(fov * .5); } /** * Returns the orbit center position, where the camera looking at. * @param out The receiving Vector3 instance to copy the result * @param receiveEndValue Whether receive the transition end coords or current. default is `true` * @category Methods */ getTarget(out, receiveEndValue = true) { return (!!out && out.isVector3 ? out : new THREE.Vector3()).copy(receiveEndValue ? this._targetEnd : this._target); } /** * Returns the camera position. * @param out The receiving Vector3 instance to copy the result * @param receiveEndValue Whether receive the transition end coords or current. default is `true` * @category Methods */ getPosition(out, receiveEndValue = true) { return (!!out && out.isVector3 ? out : new THREE.Vector3()).setFromSpherical(receiveEndValue ? this._sphericalEnd : this._spherical).applyQuaternion(this._yAxisUpSpaceInverse).add(receiveEndValue ? this._targetEnd : this._target); } /** * Returns the spherical coordinates of the orbit. * @param out The receiving Spherical instance to copy the result * @param receiveEndValue Whether receive the transition end coords or current. default is `true` * @category Methods */ getSpherical(out, receiveEndValue = true) { return (out || new THREE.Spherical()).copy(receiveEndValue ? this._sphericalEnd : this._spherical); } /** * Returns the focal offset, which is how much the camera appears to be translated in screen parallel coordinates. * @param out The receiving Vector3 instance to copy the result * @param receiveEndValue Whether receive the transition end coords or current. default is `true` * @category Methods */ getFocalOffset(out, receiveEndValue = true) { return (!!out && out.isVector3 ? out : new THREE.Vector3()).copy(receiveEndValue ? this._focalOffsetEnd : this._focalOffset); } /** * Normalize camera azimuth angle (horizontal rotation) between -180 and 180 degrees. * @returns This CameraControls instance. * @category Methods */ normalizeRotations() { this._sphericalEnd.theta = (this._sphericalEnd.theta % PI_2 + PI_2) % PI_2; if (this._sphericalEnd.theta > Math.PI) this._sphericalEnd.theta -= PI_2; this._spherical.theta += PI_2 * Math.round((this._sphericalEnd.theta - this._spherical.theta) / PI_2); return this; } /** * stop all transitions. */ stop() { this._focalOffset.copy(this._focalOffsetEnd); this._target.copy(this._targetEnd); this._spherical.copy(this._sphericalEnd); this._zoom = this._zoomEnd; } /** * Reset all rotation and position to defaults. * @param enableTransition * @category Methods */ reset(enableTransition = false) { if (!approxEquals(this._camera.up.x, this._cameraUp0.x) || !approxEquals(this._camera.up.y, this._cameraUp0.y) || !approxEquals(this._camera.up.z, this._cameraUp0.z)) { this._camera.up.copy(this._cameraUp0); const position = this.getPosition(_v3A); this.updateCameraUp(); this.setPosition(position.x, position.y, position.z); } const promises = [ this.setLookAt(this._position0.x, this._position0.y, this._position0.z, this._target0.x, this._target0.y, this._target0.z, enableTransition), this.setFocalOffset(this._focalOffset0.x, this._focalOffset0.y, this._focalOffset0.z, enableTransition), this.zoomTo(this._zoom0, enableTransition) ]; return Promise.all(promises); } /** * Set current camera position as the default position. * @category Methods */ saveState() { this._cameraUp0.copy(this._camera.up); this.getTarget(this._target0); this.getPosition(this._position0); this._zoom0 = this._zoom; this._focalOffset0.copy(this._focalOffset); } /** * Sync camera-up direction. * When camera-up vector is changed, `.updateCameraUp()` must be called. * @category Methods */ updateCameraUp() { this._yAxisUpSpace.setFromUnitVectors(this._camera.up, _AXIS_Y); this._yAxisUpSpaceInverse.copy(this._yAxisUpSpace).invert(); } /** * Apply current camera-up direction to the camera. * The orbit system will be re-initialized with the current position. * @category Methods */ applyCameraUp() { const cameraDirection = _v3A.subVectors(this._target, this._camera.position).normalize(); const side = _v3B.crossVectors(cameraDirection, this._camera.up); this._camera.up.crossVectors(side, cameraDirection).normalize(); this._camera.updateMatrixWorld(); const position = this.getPosition(_v3A); this.updateCameraUp(); this.setPosition(position.x, position.y, position.z); } /** * Update camera position and directions. * This should be called in your tick loop every time, and returns true if re-rendering is needed. * @param delta * @returns updated * @category Methods */ update(delta) { const deltaTheta = this._sphericalEnd.theta - this._spherical.theta; const deltaPhi = this._sphericalEnd.phi - this._spherical.phi; const deltaRadius = this._sphericalEnd.radius - this._spherical.radius; const deltaTarget = _deltaTarget.subVectors(this._targetEnd, this._target); const deltaOffset = _deltaOffset.subVectors(this._focalOffsetEnd, this._focalOffset); const deltaZoom = this._zoomEnd - this._zoom; if (approxZero(deltaTheta)) { this._thetaVelocity.value = 0; this._spherical.theta = this._sphericalEnd.theta; } else { const smoothTime = this._isUserControllingRotate ? this.draggingSmoothTime : this.smoothTime; this._spherical.theta = smoothDamp(this._spherical.theta, this._sphericalEnd.theta, this._thetaVelocity, smoothTime, Infinity, delta); this._needsUpdate = true; } if (approxZero(deltaPhi)) { this._phiVelocity.value = 0; this._spherical.phi = this._sphericalEnd.phi; } else { const smoothTime = this._isUserControllingRotate ? this.draggingSmoothTime : this.smoothTime; this._spherical.phi = smoothDamp(this._spherical.phi, this._sphericalEnd.phi, this._phiVelocity, smoothTime, Infinity, delta); this._needsUpdate = true; } if (approxZero(deltaRadius)) { this._radiusVelocity.value = 0; this._spherical.radius = this._sphericalEnd.radius; } else { const smoothTime = this._isUserControllingDolly ? this.draggingSmoothTime : this.smoothTime; this._spherical.radius = smoothDamp(this._spherical.radius, this._sphericalEnd.radius, this._radiusVelocity, smoothTime, this.maxSpeed, delta); this._needsUpdate = true; } if (approxZero(deltaTarget.x) && approxZero(deltaTarget.y) && approxZero(deltaTarget.z)) { this._targetVelocity.set(0, 0, 0); this._target.copy(this._targetEnd); } else { const smoothTime = this._isUserControllingTruck ? this.draggingSmoothTime : this.smoothTime; smoothDampVec3(this._target, this._targetEnd, this._targetVelocity, smoothTime, this.maxSpeed, delta, this._target); this._needsUpdate = true; } if (approxZero(deltaOffset.x) && approxZero(deltaOffset.y) && approxZero(deltaOffset.z)) { this._focalOffsetVelocity.set(0, 0, 0); this._focalOffset.copy(this._focalOffsetEnd); } else { const smoothTime = this._isUserControllingOffset ? this.draggingSmoothTime : this.smoothTime; smoothDampVec3(this._focalOffset, this._focalOffsetEnd, this._focalOffsetVelocity, smoothTime, this.maxSpeed, delta, this._focalOffset); this._needsUpdate = true; } if (approxZero(deltaZoom)) { this._zoomVelocity.value = 0; this._zoom = this._zoomEnd; } else { const smoothTime = this._isUserControllingZoom ? this.draggingSmoothTime : this.smoothTime; this._zoom = smoothDamp(this._zoom, this._zoomEnd, this._zoomVelocity, smoothTime, Infinity, delta); } if (this.dollyToCursor) { if (isPerspectiveCamera(this._camera) && this._changedDolly !== 0) { const dollyControlAmount = this._spherical.radius - this._lastDistance; const camera = this._camera; const cameraDirection = this._getCameraDirection(_cameraDirection); const planeX = _v3A.copy(cameraDirection).cross(camera.up).normalize(); if (planeX.lengthSq() === 0) planeX.x = 1; const planeY = _v3B.crossVectors(planeX, cameraDirection); const worldToScreen = this._sphericalEnd.radius * Math.tan(camera.getEffectiveFOV() * DEG2RAD * .5); const lerpRatio = (this._sphericalEnd.radius - dollyControlAmount - this._sphericalEnd.radius) / this._sphericalEnd.radius; const cursor = _v3C.copy(this._targetEnd).add(planeX.multiplyScalar(this._dollyControlCoord.x * worldToScreen * camera.aspect)).add(planeY.multiplyScalar(this._dollyControlCoord.y * worldToScreen)); const newTargetEnd = _v3A.copy(this._targetEnd).lerp(cursor, lerpRatio); const isMin = this._lastDollyDirection === DOLLY_DIRECTION.IN && this._spherical.radius <= this.minDistance; const isMax = this._lastDollyDirection === DOLLY_DIRECTION.OUT && this.maxDistance <= this._spherical.radius; if (this.infinityDolly && (isMin || isMax)) { this._sphericalEnd.radius -= dollyControlAmount; this._spherical.radius -= dollyControlAmount; const dollyAmount = _v3B.copy(cameraDirection).multiplyScalar(-dollyControlAmount); newTargetEnd.add(dollyAmount); } this._boundary.clampPoint(newTargetEnd, newTargetEnd); const targetEndDiff = _v3B.subVectors(newTargetEnd, this._targetEnd); this._targetEnd.copy(newTargetEnd); this._target.add(targetEndDiff); this._changedDolly -= dollyControlAmount; if (approxZero(this._changedDolly)) this._changedDolly = 0; } else if (isOrthographicCamera$1(this._camera) && this._changedZoom !== 0) { const dollyControlAmount = this._zoom - this._lastZoom; const camera = this._camera; const worldCursorPosition = _v3A.set(this._dollyControlCoord.x, this._dollyControlCoord.y, (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera); const quaternion = _v3B.set(0, 0, -1).applyQuaternion(camera.quaternion); const cursor = _v3C.copy(worldCursorPosition).add(quaternion.multiplyScalar(-worldCursorPosition.dot(camera.up))); const lerpRatio = -(this._zoom - dollyControlAmount - this._zoom) / this._zoom; const cameraDirection = this._getCameraDirection(_cameraDirection); const prevPlaneConstant = this._targetEnd.dot(cameraDirection); const newTargetEnd = _v3A.copy(this._targetEnd).lerp(cursor, lerpRatio); const newPlaneConstant = newTargetEnd.dot(cameraDirection); const pullBack = cameraDirection.multiplyScalar(newPlaneConstant - prevPlaneConstant); newTargetEnd.sub(pullBack); this._boundary.clampPoint(newTargetEnd, newTargetEnd); const targetEndDiff = _v3B.subVectors(newTargetEnd, this._targetEnd); this._targetEnd.copy(newTargetEnd); this._target.add(targetEndDiff); this._changedZoom -= dollyControlAmount; if (approxZero(this._changedZoom)) this._changedZoom = 0; } } if (this._camera.zoom !== this._zoom) { this._camera.zoom = this._zoom; this._camera.updateProjectionMatrix(); this._updateNearPlaneCorners(); this._needsUpdate = true; } this._dragNeedsUpdate = true; const maxDistance = this._collisionTest(); this._spherical.radius = Math.min(this._spherical.radius, maxDistance); this._spherical.makeSafe(); this._camera.position.setFromSpherical(this._spherical).applyQuaternion(this._yAxisUpSpaceInverse).add(this._target); this._camera.lookAt(this._target); if (!approxZero(this._focalOffset.x) || !approxZero(this._focalOffset.y) || !approxZero(this._focalOffset.z)) { this._camera.matrix.compose(this._camera.position, this._camera.quaternion, this._camera.scale); _xColumn.setFromMatrixColumn(this._camera.matrix, 0); _yColumn.setFromMatrixColumn(this._camera.matrix, 1); _zColumn.setFromMatrixColumn(this._camera.matrix, 2); _xColumn.multiplyScalar(this._focalOffset.x); _yColumn.multiplyScalar(-this._focalOffset.y); _zColumn.multiplyScalar(this._focalOffset.z); _v3A.copy(_xColumn).add(_yColumn).add(_zColumn); this._camera.position.add(_v3A); this._camera.updateMatrixWorld(); } if (this._boundaryEnclosesCamera) this._encloseToBoundary(this._camera.position.copy(this._target), _v3A.setFromSpherical(this._spherical).applyQuaternion(this._yAxisUpSpaceInverse), 1); const updated = this._needsUpdate; if (updated && !this._updatedLastTime) { this._hasRested = false; this.dispatchEvent({ type: "wake" }); this.dispatchEvent({ type: "update" }); } else if (updated) { this.dispatchEvent({ type: "update" }); if (approxZero(deltaTheta, this.restThreshold) && approxZero(deltaPhi, this.restThreshold) && approxZero(deltaRadius, this.restThreshold) && approxZero(deltaTarget.x, this.restThreshold) && approxZero(deltaTarget.y, this.restThreshold) && approxZero(deltaTarget.z, this.restThreshold) && approxZero(deltaOffset.x, this.restThreshold) && approxZero(deltaOffset.y, this.restThreshold) && approxZero(deltaOffset.z, this.restThreshold) && approxZero(deltaZoom, this.restThreshold) && !this._hasRested) { this._hasRested = true; this.dispatchEvent({ type: "rest" }); } } else if (!updated && this._updatedLastTime) this.dispatchEvent({ type: "sleep" }); this._lastDistance = this._spherical.radius; this._lastZoom = this._zoom; this._updatedLastTime = updated; this._needsUpdate = false; return updated; } /** * Get all state in JSON string * @category Methods */ toJSON() { return JSON.stringify({ enabled: this._enabled, minDistance: this.minDistance, maxDistance: infinityToMaxNumber(this.maxDistance), minZoom: this.minZoom, maxZoom: infinityToMaxNumber(this.maxZoom), minPolarAngle: this.minPolarAngle, maxPolarAngle: infinityToMaxNumber(this.maxPolarAngle), minAzimuthAngle: infinityToMaxNumber(this.minAzimuthAngle), maxAzimuthAngle: infinityToMaxNumber(this.maxAzimuthAngle), smoothTime: this.smoothTime, draggingSmoothTime: this.draggingSmoothTime, dollySpeed: this.dollySpeed, truckSpeed: this.truckSpeed, dollyToCursor: this.dollyToCursor, target: this._targetEnd.toArray(), position: _v3A.setFromSpherical(this._sphericalEnd).add(this._targetEnd).toArray(), zoom: this._zoomEnd, focalOffset: this._focalOffsetEnd.toArray(), target0: this._target0.toArray(), position0: this._position0.toArray(), zoom0: this._zoom0, focalOffset0: this._focalOffset0.toArray() }); } /** * Reproduce the control state with JSON. enableTransition is where anim or not in a boolean. * @param json * @param enableTransition * @category Methods */ fromJSON(json, enableTransition = false) { const obj = JSON.parse(json); this.enabled = obj.enabled; this.minDistance = obj.minDistance; this.maxDistance = maxNumberToInfinity(obj.maxDistance); this.minZoom = obj.minZoom; this.maxZoom = maxNumberToInfinity(obj.maxZoom); this.minPolarAngle = obj.minPolarAngle; this.maxPolarAngle = maxNumberToInfinity(obj.maxPolarAngle); this.minAzimuthAngle = maxNumberToInfinity(obj.minAzimuthAngle); this.maxAzimuthAngle = maxNumberToInfinity(obj.maxAzimuthAngle); this.smoothTime = obj.smoothTime; this.draggingSmoothTime = obj.draggingSmoothTime; this.dollySpeed = obj.dollySpeed; this.truckSpeed = obj.truckSpeed; this.dollyToCursor = obj.dollyToCursor; this._target0.fromArray(obj.target0); this._position0.fromArray(obj.position0); this._zoom0 = obj.zoom0; this._focalOffset0.fromArray(obj.focalOffset0); this.moveTo(obj.target[0], obj.target[1], obj.target[2], enableTransition); _sphericalA.setFromVector3(_v3A.fromArray(obj.position).sub(this._targetEnd).applyQuaternion(this._yAxisUpSpace)); this.rotateTo(_sphericalA.theta, _sphericalA.phi, enableTransition); this.dollyTo(_sphericalA.radius, enableTransition); this.zoomTo(obj.zoom, enableTransition); this.setFocalOffset(obj.focalOffset[0], obj.focalOffset[1], obj.focalOffset[2], enableTransition); this._needsUpdate = true; } /** * Attach all internal event handlers to enable drag control. * @category Methods */ connect(domElement) { if (this._domElement) { console.warn("camera-controls is already connected."); return; } domElement.setAttribute("data-camera-controls-version", VERSION); this._addAllEventListeners(domElement); this._getClientRect(this._elementRect); } /** * Detach all internal event handlers to disable drag control. */ disconnect() { this.cancel(); this._removeAllEventListeners(); if (this._domElement) { this._domElement.removeAttribute("data-camera-controls-version"); this._domElement = void 0; } } /** * Dispose the cameraControls instance itself, remove all eventListeners. * @category Methods */ dispose() { this.removeAllEventListeners(); this.disconnect(); } _getTargetDirection(out) { return out.setFromSpherical(this._spherical).divideScalar(this._spherical.radius).applyQuaternion(this._yAxisUpSpaceInverse); } _getCameraDirection(out) { return this._getTargetDirection(out).negate(); } _findPointerById(pointerId) { return this._activePointers.find((activePointer) => activePointer.pointerId === pointerId); } _findPointerByMouseButton(mouseButton) { return this._activePointers.find((activePointer) => activePointer.mouseButton === mouseButton); } _disposePointer(pointer) { this._activePointers.splice(this._activePointers.indexOf(pointer), 1); } _encloseToBoundary(position, offset, friction) { const offsetLength2 = offset.lengthSq(); if (offsetLength2 === 0) return position; const newTarget = _v3B.copy(offset).add(position); const deltaClampedTarget = this._boundary.clampPoint(newTarget, _v3C).sub(newTarget); const deltaClampedTargetLength2 = deltaClampedTarget.lengthSq(); if (deltaClampedTargetLength2 === 0) return position.add(offset); else if (deltaClampedTargetLength2 === offsetLength2) return position; else if (friction === 0) return position.add(offset).add(deltaClampedTarget); else { const offsetFactor = 1 + friction * deltaClampedTargetLength2 / offset.dot(deltaClampedTarget); return position.add(_v3B.copy(offset).multiplyScalar(offsetFactor)).add(deltaClampedTarget.multiplyScalar(1 - friction)); } } _updateNearPlaneCorners() { if (isPerspectiveCamera(this._camera)) { const camera = this._camera; const near = camera.near; const fov = camera.getEffectiveFOV() * DEG2RAD; const heightHalf = Math.tan(fov * .5) * near; const widthHalf = heightHalf * camera.aspect; this._nearPlaneCorners[0].set(-widthHalf, -heightHalf, 0); this._nearPlaneCorners[1].set(widthHalf, -heightHalf, 0); this._nearPlaneCorners[2].set(widthHalf, heightHalf, 0); this._nearPlaneCorners[3].set(-widthHalf, heightHalf, 0); } else if (isOrthographicCamera$1(this._camera)) { const camera = this._camera; const zoomInv = 1 / camera.zoom; const left = camera.left * zoomInv; const right = camera.right * zoomInv; const top = camera.top * zoomInv; const bottom = camera.bottom * zoomInv; this._nearPlaneCorners[0].set(left, top, 0); this._nearPlaneCorners[1].set(right, top, 0); this._nearPlaneCorners[2].set(right, bottom, 0); this._nearPlaneCorners[3].set(left, bottom, 0); } } _truckInternal = (deltaX, deltaY, dragToOffset, screenSpacePanning) => { let truckX; let pedestalY; if (isPerspectiveCamera(this._camera)) { const offset = _v3A.copy(this._camera.position).sub(this._target); const fov = this._camera.getEffectiveFOV() * DEG2RAD; const targetDistance = offset.length() * Math.tan(fov * .5); truckX = this.truckSpeed * deltaX * targetDistance / this._elementRect.height; pedestalY = this.truckSpeed * deltaY * targetDistance / this._elementRect.height; } else if (isOrthographicCamera$1(this._camera)) { const camera = this._camera; truckX = this.truckSpeed * deltaX * (camera.right - camera.left) / camera.zoom / this._elementRect.width; pedestalY = this.truckSpeed * deltaY * (camera.top - camera.bottom) / camera.zoom / this._elementRect.height; } else return; if (screenSpacePanning) { dragToOffset ? this.setFocalOffset(this._focalOffsetEnd.x + truckX, this._focalOffsetEnd.y, this._focalOffsetEnd.z, true) : this.truck(truckX, 0, true); this.forward(-pedestalY, true); } else dragToOffset ? this.setFocalOffset(this._focalOffsetEnd.x + truckX, this._focalOffsetEnd.y + pedestalY, this._focalOffsetEnd.z, true) : this.truck(truckX, pedestalY, true); }; _rotateInternal = (deltaX, deltaY) => { const theta = PI_2 * this.azimuthRotateSpeed * deltaX / this._elementRect.height; const phi = PI_2 * this.polarRotateSpeed * deltaY / this._elementRect.height; this.rotate(theta, phi, true); }; _dollyInternal = (delta, x, y) => { const dollyScale = Math.pow(.95, -delta * this.dollySpeed); const lastDistance = this._sphericalEnd.radius; const distance = this._sphericalEnd.radius * dollyScale; const clampedDistance = clamp(distance, this.minDistance, this.maxDistance); const overflowedDistance = clampedDistance - distance; if (this.infinityDolly && this.dollyToCursor) this._dollyToNoClamp(distance, true); else if (this.infinityDolly && !this.dollyToCursor) { this.dollyInFixed(overflowedDistance, true); this._dollyToNoClamp(clampedDistance, true); } else this._dollyToNoClamp(clampedDistance, true); if (this.dollyToCursor) { this._changedDolly += (this.infinityDolly ? distance : clampedDistance) - lastDistance; this._dollyControlCoord.set(x, y); } this._lastDollyDirection = Math.sign(-delta); }; _zoomInternal = (delta, x, y) => { const zoomScale = Math.pow(.95, delta * this.dollySpeed); const lastZoom = this._zoom; const zoom = this._zoom * zoomScale; this.zoomTo(zoom, true); if (this.dollyToCursor) { this._changedZoom += zoom - lastZoom; this._dollyControlCoord.set(x, y); } }; _collisionTest() { let distance = Infinity; if (!(this.colliderMeshes.length >= 1)) return distance; if (notSupportedInOrthographicCamera(this._camera, "_collisionTest")) return distance; const rayDirection = this._getTargetDirection(_cameraDirection); _rotationMatrix.lookAt(_ORIGIN, rayDirection, this._camera.up); for (let i = 0; i < 4; i++) { const nearPlaneCorner = _v3B.copy(this._nearPlaneCorners[i]); nearPlaneCorner.applyMatrix4(_rotationMatrix); const origin = _v3C.addVectors(this._target, nearPlaneCorner); _raycaster.set(origin, rayDirection); _raycaster.far = this._spherical.radius + 1; const intersects = _raycaster.intersectObjects(this.colliderMeshes); if (intersects.length !== 0 && intersects[0].distance < distance) distance = intersects[0].distance; } return distance; } /** * Get its client rect and package into given `DOMRect` . */ _getClientRect(target) { if (!this._domElement) return; const rect = this._domElement.getBoundingClientRect(); target.x = rect.left; target.y = rect.top; if (this._viewport) { target.x += this._viewport.x; target.y += rect.height - this._viewport.w - this._viewport.y; target.width = this._viewport.z; target.height = this._viewport.w; } else { target.width = rect.width; target.height = rect.height; } return target; } _createOnRestPromise(resolveImmediately) { if (resolveImmediately) return Promise.resolve(); this._hasRested = false; this.dispatchEvent({ type: "transitionstart" }); return new Promise((resolve) => { const onResolve = () => { this.removeEventListener("rest", onResolve); resolve(); }; this.addEventListener("rest", onResolve); }); } _addAllEventListeners(_domElement) {} _removeAllEventListeners() {} /** * backward compatible * @deprecated use smoothTime (in seconds) instead * @category Properties */ get dampingFactor() { console.warn(".dampingFactor has been deprecated. use smoothTime (in seconds) instead."); return 0; } /** * backward compatible * @deprecated use smoothTime (in seconds) instead * @category Properties */ set dampingFactor(_) { console.warn(".dampingFactor has been deprecated. use smoothTime (in seconds) instead."); } /** * backward compatible * @deprecated use draggingSmoothTime (in seconds) instead * @category Properties */ get draggingDampingFactor() { console.warn(".draggingDampingFactor has been deprecated. use draggingSmoothTime (in seconds) instead."); return 0; } /** * backward compatible * @deprecated use draggingSmoothTime (in seconds) instead * @category Properties */ set draggingDampingFactor(_) { console.warn(".draggingDampingFactor has been deprecated. use draggingSmoothTime (in seconds) instead."); } static createBoundingSphere(object3d, out = new THREE.Sphere()) { const boundingSphere = out; const center = boundingSphere.center; _box3A.makeEmpty(); object3d.traverseVisible((object) => { if (!object.isMesh) return; _box3A.expandByObject(object); }); _box3A.getCenter(center); let maxRadiusSq = 0; object3d.traverseVisible((object) => { if (!object.isMesh) return; const mesh = object; if (!mesh.geometry) return; const geometry = mesh.geometry.clone(); geometry.applyMatrix4(mesh.matrixWorld); const position = geometry.attributes.position; for (let i = 0, l = position.count; i < l; i++) { _v3A.fromBufferAttribute(position, i); maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_v3A)); } }); boundingSphere.radius = Math.sqrt(maxRadiusSq); return boundingSphere; } }; //#endregion //#region node_modules/@react-three/drei/core/CameraControls.js var CameraControls = /* @__PURE__ */ (0, import_react.forwardRef)((props, ref) => { const { impl: SubclassImpl, camera, domElement, makeDefault, onControlStart, onControl, onControlEnd, onTransitionStart, onUpdate, onWake, onRest, onSleep, onStart, onEnd, onChange, regress, ...restProps } = props; const Impl = SubclassImpl !== null && SubclassImpl !== void 0 ? SubclassImpl : CameraControls$1; (0, import_react.useMemo)(() => { const subsetOfTHREE = { Box3, MathUtils: { clamp: MathUtils.clamp }, Matrix4, Quaternion, Raycaster, Sphere: Sphere$1, Spherical, Vector2, Vector3, Vector4 }; Impl.install({ THREE: subsetOfTHREE }); extend({ CameraControlsImpl: Impl }); }, [Impl]); const defaultCamera = useThree((state) => state.camera); const gl = useThree((state) => state.gl); const invalidate = useThree((state) => state.invalidate); const events = useThree((state) => state.events); const setEvents = useThree((state) => state.setEvents); const set = useThree((state) => state.set); const get = useThree((state) => state.get); const performance = useThree((state) => state.performance); const explCamera = camera || defaultCamera; const explDomElement = domElement || events.connected || gl.domElement; const controls = (0, import_react.useMemo)(() => new Impl(explCamera), [Impl, explCamera]); useFrame((state, delta) => { controls.update(delta); }, -1); (0, import_react.useEffect)(() => { controls.connect(explDomElement); return () => void controls.disconnect(); }, [explDomElement, controls]); (0, import_react.useEffect)(() => { function invalidateAndRegress() { invalidate(); if (regress) performance.regress(); } const handleControlStart = (e) => { invalidateAndRegress(); onControlStart?.(e); onStart?.(e); }; const handleControl = (e) => { invalidateAndRegress(); onControl?.(e); onChange?.(e); }; const handleControlEnd = (e) => { onControlEnd?.(e); onEnd?.(e); }; const handleTransitionStart = (e) => { invalidateAndRegress(); onTransitionStart?.(e); onChange?.(e); }; const handleUpdate = (e) => { invalidateAndRegress(); onUpdate?.(e); onChange?.(e); }; const handleWake = (e) => { invalidateAndRegress(); onWake?.(e); onChange?.(e); }; const handleRest = (e) => { onRest?.(e); }; const handleSleep = (e) => { onSleep?.(e); }; controls.addEventListener("controlstart", handleControlStart); controls.addEventListener("control", handleControl); controls.addEventListener("controlend", handleControlEnd); controls.addEventListener("transitionstart", handleTransitionStart); controls.addEventListener("update", handleUpdate); controls.addEventListener("wake", handleWake); controls.addEventListener("rest", handleRest); controls.addEventListener("sleep", handleSleep); return () => { controls.removeEventListener("controlstart", handleControlStart); controls.removeEventListener("control", handleControl); controls.removeEventListener("controlend", handleControlEnd); controls.removeEventListener("transitionstart", handleTransitionStart); controls.removeEventListener("update", handleUpdate); controls.removeEventListener("wake", handleWake); controls.removeEventListener("rest", handleRest); controls.removeEventListener("sleep", handleSleep); }; }, [ controls, invalidate, setEvents, regress, performance, onControlStart, onControl, onControlEnd, onTransitionStart, onUpdate, onWake, onRest, onSleep, onChange, onStart, onEnd ]); (0, import_react.useEffect)(() => { if (makeDefault) { const old = get().controls; set({ controls }); return () => set({ controls: old }); } }, [makeDefault, controls]); return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ ref, object: controls }, restProps)); }); //#endregion //#region node_modules/@react-three/drei/core/MotionPathControls.js var isObject3DRef = (ref) => (ref == null ? void 0 : ref.current) instanceof Object3D; var MotionContext = /* @__PURE__ */ import_react.createContext(null); function useMotion() { const context = import_react.useContext(MotionContext); if (!context) throw new Error("useMotion hook must be used in a MotionPathControls component."); return context; } function Debug({ points = 50, color = "black" }) { const { path } = useMotion(); const [dots, setDots] = import_react.useState([]); const material = import_react.useMemo(() => new MeshBasicMaterial({ color }), [color]); const geometry = import_react.useMemo(() => new SphereGeometry(.025, 16, 16), []); const last = import_react.useRef([]); import_react.useEffect(() => { if (path.curves !== last.current) { setDots(path.getPoints(points)); last.current = path.curves; } }); return dots.map((item, index) => /*#__PURE__*/ import_react.createElement("mesh", { key: index, material, geometry, position: [ item.x, item.y, item.z ] })); } var MotionPathControls = /* @__PURE__ */ import_react.forwardRef(({ children, curves = [], debug = false, debugColor = "black", object, focus, loop = true, offset = void 0, smooth = false, eps = 1e-5, damping = .1, focusDamping = .1, maxSpeed = Infinity, ...props }, fref) => { const { camera } = useThree(); const ref = import_react.useRef(null); const pos = import_react.useRef(offset !== null && offset !== void 0 ? offset : 0); const path = import_react.useMemo(() => new CurvePath(), []); const state = import_react.useMemo(() => ({ focus, object: (object == null ? void 0 : object.current) instanceof Object3D ? object : { current: camera }, path, current: pos.current, offset: pos.current, point: new Vector3(), tangent: new Vector3(), next: new Vector3() }), [focus, object]); const instanceRef = useInstanceHandle(ref); import_react.useLayoutEffect(() => { const instance = instanceRef.current; path.curves = []; const _curves = curves.length > 0 ? curves : instance.children.map((instance) => instance.object); for (let i = 0; i < _curves.length; i++) path.add(_curves[i]); if (smooth) path.curves = [new CatmullRomCurve3(path.getPoints(typeof smooth === "number" ? smooth : 1))]; path.updateArcLengths(); }); import_react.useImperativeHandle(fref, () => Object.assign(ref.current, { motion: state }), [state]); import_react.useLayoutEffect(() => { pos.current = misc.repeat(pos.current, 1); }, [offset]); const vec = import_react.useMemo(() => new Vector3(), []); useFrame((_state, delta) => { const lastOffset = state.offset; easing.damp(pos, "current", offset !== void 0 ? offset : state.current, damping, delta, maxSpeed, void 0, eps); state.offset = loop ? misc.repeat(pos.current, 1) : misc.clamp(pos.current, 0, 1); if (path.getCurveLengths().length > 0) { path.getPointAt(state.offset, state.point); path.getTangentAt(state.offset, state.tangent).normalize(); path.getPointAt(misc.repeat(pos.current - (lastOffset - state.offset), 1), state.next); const target = (object == null ? void 0 : object.current) instanceof Object3D ? object.current : camera; target.position.copy(state.point); if (focus) easing.dampLookAt(target, isObject3DRef(focus) ? focus.current.getWorldPosition(vec) : focus, focusDamping, delta, maxSpeed, void 0, eps); } }); return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement(MotionContext.Provider, { value: state }, children, debug && /*#__PURE__*/ import_react.createElement(Debug, { color: debugColor }))); }); //#endregion //#region node_modules/@react-three/drei/core/Hud.js function RenderHud({ defaultScene, defaultCamera, renderPriority = 1 }) { const { gl, scene, camera } = useThree(); let oldCLear; useFrame(() => { oldCLear = gl.autoClear; if (renderPriority === 1) { gl.autoClear = true; gl.render(defaultScene, defaultCamera); } gl.autoClear = false; gl.clearDepth(); gl.render(scene, camera); gl.autoClear = oldCLear; }, renderPriority); return /*#__PURE__*/ import_react.createElement("group", { onPointerOver: () => null }); } function Hud({ children, renderPriority = 1 }) { const { scene: defaultScene, camera: defaultCamera } = useThree(); const [hudScene] = import_react.useState(() => new Scene()); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, createPortal(/*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children, /*#__PURE__*/ import_react.createElement(RenderHud, { defaultScene, defaultCamera, renderPriority })), hudScene, { events: { priority: renderPriority + 1 } })); } //#endregion //#region node_modules/@react-three/drei/core/GizmoHelper.js var Context = /* @__PURE__ */ import_react.createContext({}); var useGizmoContext = () => { return import_react.useContext(Context); }; var turnRate = 2 * Math.PI; var dummy = /* @__PURE__ */ new Object3D(); var matrix = /* @__PURE__ */ new Matrix4(); var [q1, q2] = [/* @__PURE__ */ new Quaternion(), /* @__PURE__ */ new Quaternion()]; var target = /* @__PURE__ */ new Vector3(); var targetPosition = /* @__PURE__ */ new Vector3(); var isOrbitControls = (controls) => { return "minPolarAngle" in controls; }; var isCameraControls = (controls) => { return "getTarget" in controls; }; var GizmoHelper = ({ alignment = "bottom-right", margin = [80, 80], renderPriority = 1, onUpdate, onTarget, children }) => { const size = useThree((state) => state.size); const mainCamera = useThree((state) => state.camera); const defaultControls = useThree((state) => state.controls); const invalidate = useThree((state) => state.invalidate); const gizmoRef = import_react.useRef(null); const virtualCam = import_react.useRef(null); const animating = import_react.useRef(false); const radius = import_react.useRef(0); const focusPoint = import_react.useRef(new Vector3(0, 0, 0)); const defaultUp = import_react.useRef(new Vector3(0, 0, 0)); import_react.useEffect(() => { defaultUp.current.copy(mainCamera.up); dummy.up.copy(mainCamera.up); }, [mainCamera]); const tweenCamera = import_react.useCallback((direction) => { animating.current = true; if (defaultControls || onTarget) focusPoint.current = (onTarget == null ? void 0 : onTarget()) || (isCameraControls(defaultControls) ? defaultControls.getTarget(focusPoint.current) : defaultControls == null ? void 0 : defaultControls.target); radius.current = mainCamera.position.distanceTo(target); q1.copy(mainCamera.quaternion); targetPosition.copy(direction).multiplyScalar(radius.current).add(target); dummy.lookAt(targetPosition); q2.copy(dummy.quaternion); invalidate(); }, [ defaultControls, mainCamera, onTarget, invalidate ]); useFrame((_, delta) => { if (virtualCam.current && gizmoRef.current) { var _gizmoRef$current; if (animating.current) if (q1.angleTo(q2) < .01) { animating.current = false; if (isOrbitControls(defaultControls)) mainCamera.up.copy(defaultUp.current); } else { const step = delta * turnRate; q1.rotateTowards(q2, step); mainCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(radius.current).add(focusPoint.current); mainCamera.up.set(0, 1, 0).applyQuaternion(q1).normalize(); mainCamera.quaternion.copy(q1); if (isCameraControls(defaultControls)) defaultControls.setPosition(mainCamera.position.x, mainCamera.position.y, mainCamera.position.z); if (onUpdate) onUpdate(); else if (defaultControls) defaultControls.update(delta); invalidate(); } matrix.copy(mainCamera.matrix).invert(); (_gizmoRef$current = gizmoRef.current) == null || _gizmoRef$current.quaternion.setFromRotationMatrix(matrix); } }); const gizmoHelperContext = import_react.useMemo(() => ({ tweenCamera }), [tweenCamera]); const [marginX, marginY] = margin; const x = alignment.endsWith("-center") ? 0 : alignment.endsWith("-left") ? -size.width / 2 + marginX : size.width / 2 - marginX; const y = alignment.startsWith("center-") ? 0 : alignment.startsWith("top-") ? size.height / 2 - marginY : -size.height / 2 + marginY; return /*#__PURE__*/ import_react.createElement(Hud, { renderPriority }, /*#__PURE__*/ import_react.createElement(Context.Provider, { value: gizmoHelperContext }, /*#__PURE__*/ import_react.createElement(OrthographicCamera, { makeDefault: true, ref: virtualCam, position: [ 0, 0, 200 ] }), /*#__PURE__*/ import_react.createElement("group", { ref: gizmoRef, position: [ x, y, 0 ] }, children))); }; //#endregion //#region node_modules/@react-three/drei/core/GizmoViewcube.js var colors = { bg: "#f0f0f0", hover: "#999", text: "black", stroke: "black" }; var defaultFaces = [ "Right", "Left", "Top", "Bottom", "Front", "Back" ]; var makePositionVector = (xyz) => new Vector3(...xyz).multiplyScalar(.38); var corners = /* @__PURE__ */ [ [ 1, 1, 1 ], [ 1, 1, -1 ], [ 1, -1, 1 ], [ 1, -1, -1 ], [ -1, 1, 1 ], [ -1, 1, -1 ], [ -1, -1, 1 ], [ -1, -1, -1 ] ].map(makePositionVector); var cornerDimensions = [ .25, .25, .25 ]; var edges = /* @__PURE__ */ [ [ 1, 1, 0 ], [ 1, 0, 1 ], [ 1, 0, -1 ], [ 1, -1, 0 ], [ 0, 1, 1 ], [ 0, 1, -1 ], [ 0, -1, 1 ], [ 0, -1, -1 ], [ -1, 1, 0 ], [ -1, 0, 1 ], [ -1, 0, -1 ], [ -1, -1, 0 ] ].map(makePositionVector); var edgeDimensions = /* @__PURE__ */ edges.map((edge) => edge.toArray().map((axis) => axis == 0 ? .5 : .25)); var FaceMaterial = ({ hover, index, font = "20px Inter var, Arial, sans-serif", faces = defaultFaces, color = colors.bg, hoverColor = colors.hover, textColor = colors.text, strokeColor = colors.stroke, opacity = 1 }) => { const gl = useThree((state) => state.gl); const texture = import_react.useMemo(() => { const canvas = document.createElement("canvas"); canvas.width = 128; canvas.height = 128; const context = canvas.getContext("2d"); context.fillStyle = color; context.fillRect(0, 0, canvas.width, canvas.height); context.strokeStyle = strokeColor; context.strokeRect(0, 0, canvas.width, canvas.height); context.font = font; context.textAlign = "center"; context.fillStyle = textColor; context.fillText(faces[index].toUpperCase(), 64, 76); return new CanvasTexture(canvas); }, [ index, faces, font, color, textColor, strokeColor ]); return /*#__PURE__*/ import_react.createElement("meshBasicMaterial", { map: texture, "map-anisotropy": gl.capabilities.getMaxAnisotropy() || 1, attach: `material-${index}`, color: hover ? hoverColor : "white", transparent: true, opacity }); }; var FaceCube = (props) => { const { tweenCamera } = useGizmoContext(); const [hover, setHover] = import_react.useState(null); const handlePointerOut = (e) => { e.stopPropagation(); setHover(null); }; const handleClick = (e) => { e.stopPropagation(); tweenCamera(e.face.normal); }; const handlePointerMove = (e) => { e.stopPropagation(); setHover(Math.floor(e.faceIndex / 2)); }; return /*#__PURE__*/ import_react.createElement("mesh", { onPointerOut: handlePointerOut, onPointerMove: handlePointerMove, onClick: props.onClick || handleClick }, [...Array(6)].map((_, index) => /*#__PURE__*/ import_react.createElement(FaceMaterial, _extends$1({ key: index, index, hover: hover === index }, props))), /*#__PURE__*/ import_react.createElement("boxGeometry", null)); }; var EdgeCube = ({ onClick, dimensions, position, hoverColor = colors.hover }) => { const { tweenCamera } = useGizmoContext(); const [hover, setHover] = import_react.useState(false); const handlePointerOut = (e) => { e.stopPropagation(); setHover(false); }; const handlePointerOver = (e) => { e.stopPropagation(); setHover(true); }; const handleClick = (e) => { e.stopPropagation(); tweenCamera(position); }; return /*#__PURE__*/ import_react.createElement("mesh", { scale: 1.01, position, onPointerOver: handlePointerOver, onPointerOut: handlePointerOut, onClick: onClick || handleClick }, /*#__PURE__*/ import_react.createElement("meshBasicMaterial", { color: hover ? hoverColor : "white", transparent: true, opacity: .6, visible: hover }), /*#__PURE__*/ import_react.createElement("boxGeometry", { args: dimensions })); }; var GizmoViewcube = (props) => { return /*#__PURE__*/ import_react.createElement("group", { scale: [ 60, 60, 60 ] }, /*#__PURE__*/ import_react.createElement(FaceCube, props), edges.map((edge, index) => /*#__PURE__*/ import_react.createElement(EdgeCube, _extends$1({ key: index, position: edge, dimensions: edgeDimensions[index] }, props))), corners.map((corner, index) => /*#__PURE__*/ import_react.createElement(EdgeCube, _extends$1({ key: index, position: corner, dimensions: cornerDimensions }, props)))); }; //#endregion //#region node_modules/@react-three/drei/core/GizmoViewport.js function Axis({ scale = [ .8, .05, .05 ], color, rotation }) { return /*#__PURE__*/ import_react.createElement("group", { rotation }, /*#__PURE__*/ import_react.createElement("mesh", { position: [ .4, 0, 0 ] }, /*#__PURE__*/ import_react.createElement("boxGeometry", { args: scale }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", { color, toneMapped: false }))); } function AxisHead({ onClick, font, disabled, arcStyle, label, labelColor, axisHeadScale = 1, ...props }) { const gl = useThree((state) => state.gl); const texture = import_react.useMemo(() => { const canvas = document.createElement("canvas"); canvas.width = 64; canvas.height = 64; const context = canvas.getContext("2d"); context.beginPath(); context.arc(32, 32, 16, 0, 2 * Math.PI); context.closePath(); context.fillStyle = arcStyle; context.fill(); if (label) { context.font = font; context.textAlign = "center"; context.fillStyle = labelColor; context.fillText(label, 32, 41); } return new CanvasTexture(canvas); }, [ arcStyle, label, labelColor, font ]); const [active, setActive] = import_react.useState(false); const scale = (label ? 1 : .75) * (active ? 1.2 : 1) * axisHeadScale; const handlePointerOver = (e) => { e.stopPropagation(); setActive(true); }; const handlePointerOut = (e) => { e.stopPropagation(); setActive(false); }; return /*#__PURE__*/ import_react.createElement("sprite", _extends$1({ scale, onPointerOver: !disabled ? handlePointerOver : void 0, onPointerOut: !disabled ? onClick || handlePointerOut : void 0 }, props), /*#__PURE__*/ import_react.createElement("spriteMaterial", { map: texture, "map-anisotropy": gl.capabilities.getMaxAnisotropy() || 1, alphaTest: .3, opacity: label ? 1 : .75, toneMapped: false })); } var GizmoViewport = ({ hideNegativeAxes, hideAxisHeads, disabled, font = "18px Inter var, Arial, sans-serif", axisColors = [ "#ff2060", "#20df80", "#2080ff" ], axisHeadScale = 1, axisScale, labels = [ "X", "Y", "Z" ], labelColor = "#000", onClick, ...props }) => { const [colorX, colorY, colorZ] = axisColors; const { tweenCamera } = useGizmoContext(); const axisHeadProps = { font, disabled, labelColor, onClick, axisHeadScale, onPointerDown: !disabled ? (e) => { tweenCamera(e.object.position); e.stopPropagation(); } : void 0 }; return /*#__PURE__*/ import_react.createElement("group", _extends$1({ scale: 40 }, props), /*#__PURE__*/ import_react.createElement(Axis, { color: colorX, rotation: [ 0, 0, 0 ], scale: axisScale }), /*#__PURE__*/ import_react.createElement(Axis, { color: colorY, rotation: [ 0, 0, Math.PI / 2 ], scale: axisScale }), /*#__PURE__*/ import_react.createElement(Axis, { color: colorZ, rotation: [ 0, -Math.PI / 2, 0 ], scale: axisScale }), !hideAxisHeads && /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorX, position: [ 1, 0, 0 ], label: labels[0] }, axisHeadProps)), /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorY, position: [ 0, 1, 0 ], label: labels[1] }, axisHeadProps)), /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorZ, position: [ 0, 0, 1 ], label: labels[2] }, axisHeadProps)), !hideNegativeAxes && /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorX, position: [ -1, 0, 0 ] }, axisHeadProps)), /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorY, position: [ 0, -1, 0 ] }, axisHeadProps)), /*#__PURE__*/ import_react.createElement(AxisHead, _extends$1({ arcStyle: colorZ, position: [ 0, 0, -1 ] }, axisHeadProps))))); }; //#endregion //#region node_modules/@react-three/drei/core/Grid.js var GridMaterial = /* @__PURE__ */ shaderMaterial({ cellSize: .5, sectionSize: 1, fadeDistance: 100, fadeStrength: 1, fadeFrom: 1, cellThickness: .5, sectionThickness: 1, cellColor: /* @__PURE__ */ new Color(), sectionColor: /* @__PURE__ */ new Color(), infiniteGrid: false, followCamera: false, worldCamProjPosition: /* @__PURE__ */ new Vector3(), worldPlanePosition: /* @__PURE__ */ new Vector3() }, ` varying vec3 localPosition; varying vec4 worldPosition; uniform vec3 worldCamProjPosition; uniform vec3 worldPlanePosition; uniform float fadeDistance; uniform bool infiniteGrid; uniform bool followCamera; void main() { localPosition = position.xzy; if (infiniteGrid) localPosition *= 1.0 + fadeDistance; worldPosition = modelMatrix * vec4(localPosition, 1.0); if (followCamera) { worldPosition.xyz += (worldCamProjPosition - worldPlanePosition); localPosition = (inverse(modelMatrix) * worldPosition).xyz; } gl_Position = projectionMatrix * viewMatrix * worldPosition; } `, ` varying vec3 localPosition; varying vec4 worldPosition; uniform vec3 worldCamProjPosition; uniform float cellSize; uniform float sectionSize; uniform vec3 cellColor; uniform vec3 sectionColor; uniform float fadeDistance; uniform float fadeStrength; uniform float fadeFrom; uniform float cellThickness; uniform float sectionThickness; float getGrid(float size, float thickness) { vec2 r = localPosition.xz / size; vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r); float line = min(grid.x, grid.y) + 1.0 - thickness; return 1.0 - min(line, 1.0); } void main() { float g1 = getGrid(cellSize, cellThickness); float g2 = getGrid(sectionSize, sectionThickness); vec3 from = worldCamProjPosition*vec3(fadeFrom); float dist = distance(from, worldPosition.xyz); float d = 1.0 - min(dist / fadeDistance, 1.0); vec3 color = mix(cellColor, sectionColor, min(1.0, sectionThickness * g2)); gl_FragColor = vec4(color, (g1 + g2) * pow(d, fadeStrength)); gl_FragColor.a = mix(0.75 * gl_FragColor.a, gl_FragColor.a, g2); if (gl_FragColor.a <= 0.0) discard; #include #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}> } `); var Grid = /* @__PURE__ */ import_react.forwardRef(({ args, cellColor = "#000000", sectionColor = "#2080ff", cellSize = .5, sectionSize = 1, followCamera = false, infiniteGrid = false, fadeDistance = 100, fadeStrength = 1, fadeFrom = 1, cellThickness = .5, sectionThickness = 1, side = 1, ...props }, fRef) => { extend({ GridMaterial }); const ref = import_react.useRef(null); import_react.useImperativeHandle(fRef, () => ref.current, []); const plane = new Plane$1(); const upVector = new Vector3(0, 1, 0); const zeroVector = new Vector3(0, 0, 0); useFrame((state) => { plane.setFromNormalAndCoplanarPoint(upVector, zeroVector).applyMatrix4(ref.current.matrixWorld); const gridMaterial = ref.current.material; const worldCamProjPosition = gridMaterial.uniforms.worldCamProjPosition; const worldPlanePosition = gridMaterial.uniforms.worldPlanePosition; plane.projectPoint(state.camera.position, worldCamProjPosition.value); worldPlanePosition.value.set(0, 0, 0).applyMatrix4(ref.current.matrixWorld); }); const uniforms1 = { cellSize, sectionSize, cellColor, sectionColor, cellThickness, sectionThickness }; const uniforms2 = { fadeDistance, fadeStrength, fadeFrom, infiniteGrid, followCamera }; return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref, frustumCulled: false }, props), /*#__PURE__*/ import_react.createElement("gridMaterial", _extends$1({ transparent: true, "extensions-derivatives": true, side }, uniforms1, uniforms2)), /*#__PURE__*/ import_react.createElement("planeGeometry", { args })); }); //#endregion //#region node_modules/@react-three/drei/core/CubeTexture.js function useCubeTexture(files, { path }) { const [cubeTexture] = useLoader(CubeTextureLoader, [files], (loader) => loader.setPath(path)); return cubeTexture; } useCubeTexture.preload = (files, { path }) => useLoader.preload(CubeTextureLoader, [files], (loader) => loader.setPath(path)); function CubeTexture({ children, files, ...options }) { const texture = useCubeTexture(files, { ...options }); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(texture)); } //#endregion //#region node_modules/@react-three/drei/core/Fbx.js function useFBX(path) { return useLoader(FBXLoader, path); } useFBX.preload = (path) => useLoader.preload(FBXLoader, path); useFBX.clear = (input) => useLoader.clear(FBXLoader, input); function Fbx({ path, ...props }) { const object = useFBX(path).children[0]; return /*#__PURE__*/ import_react.createElement(Clone, _extends$1({}, props, { object })); } //#endregion //#region node_modules/@react-three/drei/core/Ktx2.js var cdn = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master"; function useKTX2(input, basisPath = `${cdn}/basis/`) { const gl = useThree((state) => state.gl); const textures = useLoader(KTX2Loader, IsObject(input) ? Object.values(input) : input, (loader) => { loader.detectSupport(gl); loader.setTranscoderPath(basisPath); }); (0, import_react.useEffect)(() => { (Array.isArray(textures) ? textures : [textures]).forEach(gl.initTexture); }, [gl, textures]); if (IsObject(input)) { const keys = Object.keys(input); const keyed = {}; keys.forEach((key) => Object.assign(keyed, { [key]: textures[keys.indexOf(key)] })); return keyed; } else return textures; } useKTX2.preload = (url, basisPath = `${cdn}/basis/`) => useLoader.preload(KTX2Loader, url, (loader) => { loader.setTranscoderPath(basisPath); }); useKTX2.clear = (input) => useLoader.clear(KTX2Loader, input); var Ktx2 = ({ children, input, basisPath }) => { const texture = useKTX2(input, basisPath); return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(texture)); }; //#endregion //#region node_modules/hls.js/dist/hls.mjs var hls_exports = /* @__PURE__ */ __exportAll({ AbrController: () => AbrController, AttrList: () => AttrList, AudioStreamController: () => AudioStreamController, AudioTrackController: () => AudioTrackController, BasePlaylistController: () => BasePlaylistController, BaseSegment: () => BaseSegment, BaseStreamController: () => BaseStreamController, BufferController: () => BufferController, CMCDController: () => CMCDController, CapLevelController: () => CapLevelController, ChunkMetadata: () => ChunkMetadata, ContentSteeringController: () => ContentSteeringController, Cues: () => Cues, DateRange: () => DateRange, EMEController: () => EMEController, ErrorActionFlags: () => ErrorActionFlags, ErrorController: () => ErrorController, ErrorDetails: () => ErrorDetails, ErrorTypes: () => ErrorTypes, Events: () => Events, FPSController: () => FPSController, FetchLoader: () => FetchLoader, Fragment: () => Fragment, Hls: () => Hls, HlsSkip: () => HlsSkip, HlsUrlParameters: () => HlsUrlParameters, KeySystemFormats: () => KeySystemFormats, KeySystems: () => KeySystems, Level: () => Level, LevelDetails: () => LevelDetails, LevelKey: () => LevelKey, LoadStats: () => LoadStats, M3U8Parser: () => M3U8Parser, MetadataSchema: () => MetadataSchema, NetworkErrorAction: () => NetworkErrorAction, Part: () => Part, PlaylistLevelType: () => PlaylistLevelType, SubtitleStreamController: () => SubtitleStreamController, SubtitleTrackController: () => SubtitleTrackController, TimelineController: () => TimelineController, XhrLoader: () => XhrLoader, default: () => Hls, fetchSupported: () => fetchSupported, getMediaSource: () => getMediaSource, isMSESupported: () => isMSESupported, isSupported: () => isSupported, requestMediaKeySystemAccess: () => requestMediaKeySystemAccess }); var isFiniteNumber = Number.isFinite || function(value) { return typeof value === "number" && isFinite(value); }; var isSafeInteger = Number.isSafeInteger || function(value) { return typeof value === "number" && Math.abs(value) <= MAX_SAFE_INTEGER; }; var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; var ErrorTypes = /*#__PURE__*/ function(ErrorTypes) { ErrorTypes["NETWORK_ERROR"] = "networkError"; ErrorTypes["MEDIA_ERROR"] = "mediaError"; ErrorTypes["KEY_SYSTEM_ERROR"] = "keySystemError"; ErrorTypes["MUX_ERROR"] = "muxError"; ErrorTypes["OTHER_ERROR"] = "otherError"; return ErrorTypes; }({}); var ErrorDetails = /*#__PURE__*/ function(ErrorDetails) { ErrorDetails["KEY_SYSTEM_NO_KEYS"] = "keySystemNoKeys"; ErrorDetails["KEY_SYSTEM_NO_ACCESS"] = "keySystemNoAccess"; ErrorDetails["KEY_SYSTEM_NO_SESSION"] = "keySystemNoSession"; ErrorDetails["KEY_SYSTEM_NO_CONFIGURED_LICENSE"] = "keySystemNoConfiguredLicense"; ErrorDetails["KEY_SYSTEM_LICENSE_REQUEST_FAILED"] = "keySystemLicenseRequestFailed"; ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED"] = "keySystemServerCertificateRequestFailed"; ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED"] = "keySystemServerCertificateUpdateFailed"; ErrorDetails["KEY_SYSTEM_SESSION_UPDATE_FAILED"] = "keySystemSessionUpdateFailed"; ErrorDetails["KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED"] = "keySystemStatusOutputRestricted"; ErrorDetails["KEY_SYSTEM_STATUS_INTERNAL_ERROR"] = "keySystemStatusInternalError"; ErrorDetails["KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR"] = "keySystemDestroyMediaKeysError"; ErrorDetails["KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR"] = "keySystemDestroyCloseSessionError"; ErrorDetails["KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR"] = "keySystemDestroyRemoveSessionError"; ErrorDetails["MANIFEST_LOAD_ERROR"] = "manifestLoadError"; ErrorDetails["MANIFEST_LOAD_TIMEOUT"] = "manifestLoadTimeOut"; ErrorDetails["MANIFEST_PARSING_ERROR"] = "manifestParsingError"; ErrorDetails["MANIFEST_INCOMPATIBLE_CODECS_ERROR"] = "manifestIncompatibleCodecsError"; ErrorDetails["LEVEL_EMPTY_ERROR"] = "levelEmptyError"; ErrorDetails["LEVEL_LOAD_ERROR"] = "levelLoadError"; ErrorDetails["LEVEL_LOAD_TIMEOUT"] = "levelLoadTimeOut"; ErrorDetails["LEVEL_PARSING_ERROR"] = "levelParsingError"; ErrorDetails["LEVEL_SWITCH_ERROR"] = "levelSwitchError"; ErrorDetails["AUDIO_TRACK_LOAD_ERROR"] = "audioTrackLoadError"; ErrorDetails["AUDIO_TRACK_LOAD_TIMEOUT"] = "audioTrackLoadTimeOut"; ErrorDetails["SUBTITLE_LOAD_ERROR"] = "subtitleTrackLoadError"; ErrorDetails["SUBTITLE_TRACK_LOAD_TIMEOUT"] = "subtitleTrackLoadTimeOut"; ErrorDetails["FRAG_LOAD_ERROR"] = "fragLoadError"; ErrorDetails["FRAG_LOAD_TIMEOUT"] = "fragLoadTimeOut"; ErrorDetails["FRAG_DECRYPT_ERROR"] = "fragDecryptError"; ErrorDetails["FRAG_PARSING_ERROR"] = "fragParsingError"; ErrorDetails["FRAG_GAP"] = "fragGap"; ErrorDetails["REMUX_ALLOC_ERROR"] = "remuxAllocError"; ErrorDetails["KEY_LOAD_ERROR"] = "keyLoadError"; ErrorDetails["KEY_LOAD_TIMEOUT"] = "keyLoadTimeOut"; ErrorDetails["BUFFER_ADD_CODEC_ERROR"] = "bufferAddCodecError"; ErrorDetails["BUFFER_INCOMPATIBLE_CODECS_ERROR"] = "bufferIncompatibleCodecsError"; ErrorDetails["BUFFER_APPEND_ERROR"] = "bufferAppendError"; ErrorDetails["BUFFER_APPENDING_ERROR"] = "bufferAppendingError"; ErrorDetails["BUFFER_STALLED_ERROR"] = "bufferStalledError"; ErrorDetails["BUFFER_FULL_ERROR"] = "bufferFullError"; ErrorDetails["BUFFER_SEEK_OVER_HOLE"] = "bufferSeekOverHole"; ErrorDetails["BUFFER_NUDGE_ON_STALL"] = "bufferNudgeOnStall"; ErrorDetails["ASSET_LIST_LOAD_ERROR"] = "assetListLoadError"; ErrorDetails["ASSET_LIST_LOAD_TIMEOUT"] = "assetListLoadTimeout"; ErrorDetails["ASSET_LIST_PARSING_ERROR"] = "assetListParsingError"; ErrorDetails["INTERSTITIAL_ASSET_ITEM_ERROR"] = "interstitialAssetItemError"; ErrorDetails["INTERNAL_EXCEPTION"] = "internalException"; ErrorDetails["INTERNAL_ABORTED"] = "aborted"; ErrorDetails["ATTACH_MEDIA_ERROR"] = "attachMediaError"; ErrorDetails["UNKNOWN"] = "unknown"; return ErrorDetails; }({}); var Events = /*#__PURE__*/ function(Events) { Events["MEDIA_ATTACHING"] = "hlsMediaAttaching"; Events["MEDIA_ATTACHED"] = "hlsMediaAttached"; Events["MEDIA_DETACHING"] = "hlsMediaDetaching"; Events["MEDIA_DETACHED"] = "hlsMediaDetached"; Events["MEDIA_ENDED"] = "hlsMediaEnded"; Events["STALL_RESOLVED"] = "hlsStallResolved"; Events["BUFFER_RESET"] = "hlsBufferReset"; Events["BUFFER_CODECS"] = "hlsBufferCodecs"; Events["BUFFER_CREATED"] = "hlsBufferCreated"; Events["BUFFER_APPENDING"] = "hlsBufferAppending"; Events["BUFFER_APPENDED"] = "hlsBufferAppended"; Events["BUFFER_EOS"] = "hlsBufferEos"; Events["BUFFERED_TO_END"] = "hlsBufferedToEnd"; Events["BUFFER_FLUSHING"] = "hlsBufferFlushing"; Events["BUFFER_FLUSHED"] = "hlsBufferFlushed"; Events["MANIFEST_LOADING"] = "hlsManifestLoading"; Events["MANIFEST_LOADED"] = "hlsManifestLoaded"; Events["MANIFEST_PARSED"] = "hlsManifestParsed"; Events["LEVEL_SWITCHING"] = "hlsLevelSwitching"; Events["LEVEL_SWITCHED"] = "hlsLevelSwitched"; Events["LEVEL_LOADING"] = "hlsLevelLoading"; Events["LEVEL_LOADED"] = "hlsLevelLoaded"; Events["LEVEL_UPDATED"] = "hlsLevelUpdated"; Events["LEVEL_PTS_UPDATED"] = "hlsLevelPtsUpdated"; Events["LEVELS_UPDATED"] = "hlsLevelsUpdated"; Events["AUDIO_TRACKS_UPDATED"] = "hlsAudioTracksUpdated"; Events["AUDIO_TRACK_SWITCHING"] = "hlsAudioTrackSwitching"; Events["AUDIO_TRACK_SWITCHED"] = "hlsAudioTrackSwitched"; Events["AUDIO_TRACK_LOADING"] = "hlsAudioTrackLoading"; Events["AUDIO_TRACK_LOADED"] = "hlsAudioTrackLoaded"; Events["AUDIO_TRACK_UPDATED"] = "hlsAudioTrackUpdated"; Events["SUBTITLE_TRACKS_UPDATED"] = "hlsSubtitleTracksUpdated"; Events["SUBTITLE_TRACKS_CLEARED"] = "hlsSubtitleTracksCleared"; Events["SUBTITLE_TRACK_SWITCH"] = "hlsSubtitleTrackSwitch"; Events["SUBTITLE_TRACK_LOADING"] = "hlsSubtitleTrackLoading"; Events["SUBTITLE_TRACK_LOADED"] = "hlsSubtitleTrackLoaded"; Events["SUBTITLE_TRACK_UPDATED"] = "hlsSubtitleTrackUpdated"; Events["SUBTITLE_FRAG_PROCESSED"] = "hlsSubtitleFragProcessed"; Events["CUES_PARSED"] = "hlsCuesParsed"; Events["NON_NATIVE_TEXT_TRACKS_FOUND"] = "hlsNonNativeTextTracksFound"; Events["INIT_PTS_FOUND"] = "hlsInitPtsFound"; Events["FRAG_LOADING"] = "hlsFragLoading"; Events["FRAG_LOAD_EMERGENCY_ABORTED"] = "hlsFragLoadEmergencyAborted"; Events["FRAG_LOADED"] = "hlsFragLoaded"; Events["FRAG_DECRYPTED"] = "hlsFragDecrypted"; Events["FRAG_PARSING_INIT_SEGMENT"] = "hlsFragParsingInitSegment"; Events["FRAG_PARSING_USERDATA"] = "hlsFragParsingUserdata"; Events["FRAG_PARSING_METADATA"] = "hlsFragParsingMetadata"; Events["FRAG_PARSED"] = "hlsFragParsed"; Events["FRAG_BUFFERED"] = "hlsFragBuffered"; Events["FRAG_CHANGED"] = "hlsFragChanged"; Events["FPS_DROP"] = "hlsFpsDrop"; Events["FPS_DROP_LEVEL_CAPPING"] = "hlsFpsDropLevelCapping"; Events["MAX_AUTO_LEVEL_UPDATED"] = "hlsMaxAutoLevelUpdated"; Events["ERROR"] = "hlsError"; Events["DESTROYING"] = "hlsDestroying"; Events["KEY_LOADING"] = "hlsKeyLoading"; Events["KEY_LOADED"] = "hlsKeyLoaded"; Events["LIVE_BACK_BUFFER_REACHED"] = "hlsLiveBackBufferReached"; Events["BACK_BUFFER_REACHED"] = "hlsBackBufferReached"; Events["STEERING_MANIFEST_LOADED"] = "hlsSteeringManifestLoaded"; Events["ASSET_LIST_LOADING"] = "hlsAssetListLoading"; Events["ASSET_LIST_LOADED"] = "hlsAssetListLoaded"; Events["INTERSTITIALS_UPDATED"] = "hlsInterstitialsUpdated"; Events["INTERSTITIALS_BUFFERED_TO_BOUNDARY"] = "hlsInterstitialsBufferedToBoundary"; Events["INTERSTITIAL_ASSET_PLAYER_CREATED"] = "hlsInterstitialAssetPlayerCreated"; Events["INTERSTITIAL_STARTED"] = "hlsInterstitialStarted"; Events["INTERSTITIAL_ASSET_STARTED"] = "hlsInterstitialAssetStarted"; Events["INTERSTITIAL_ASSET_ENDED"] = "hlsInterstitialAssetEnded"; Events["INTERSTITIAL_ASSET_ERROR"] = "hlsInterstitialAssetError"; Events["INTERSTITIAL_ENDED"] = "hlsInterstitialEnded"; Events["INTERSTITIALS_PRIMARY_RESUMED"] = "hlsInterstitialsPrimaryResumed"; Events["PLAYOUT_LIMIT_REACHED"] = "hlsPlayoutLimitReached"; Events["EVENT_CUE_ENTER"] = "hlsEventCueEnter"; return Events; }({}); /** * Defines each Event type and payload by Event name. Used in {@link hls.js#HlsEventEmitter} to strongly type the event listener API. */ var PlaylistContextType = { MANIFEST: "manifest", LEVEL: "level", AUDIO_TRACK: "audioTrack", SUBTITLE_TRACK: "subtitleTrack" }; var PlaylistLevelType = { MAIN: "main", AUDIO: "audio", SUBTITLE: "subtitle" }; var EWMA = class { constructor(halfLife, estimate = 0, weight = 0) { this.halfLife = void 0; this.alpha_ = void 0; this.estimate_ = void 0; this.totalWeight_ = void 0; this.halfLife = halfLife; this.alpha_ = halfLife ? Math.exp(Math.log(.5) / halfLife) : 0; this.estimate_ = estimate; this.totalWeight_ = weight; } sample(weight, value) { const adjAlpha = Math.pow(this.alpha_, weight); this.estimate_ = value * (1 - adjAlpha) + adjAlpha * this.estimate_; this.totalWeight_ += weight; } getTotalWeight() { return this.totalWeight_; } getEstimate() { if (this.alpha_) { const zeroFactor = 1 - Math.pow(this.alpha_, this.totalWeight_); if (zeroFactor) return this.estimate_ / zeroFactor; } return this.estimate_; } }; var EwmaBandWidthEstimator = class { constructor(slow, fast, defaultEstimate, defaultTTFB = 100) { this.defaultEstimate_ = void 0; this.minWeight_ = void 0; this.minDelayMs_ = void 0; this.slow_ = void 0; this.fast_ = void 0; this.defaultTTFB_ = void 0; this.ttfb_ = void 0; this.defaultEstimate_ = defaultEstimate; this.minWeight_ = .001; this.minDelayMs_ = 50; this.slow_ = new EWMA(slow); this.fast_ = new EWMA(fast); this.defaultTTFB_ = defaultTTFB; this.ttfb_ = new EWMA(slow); } update(slow, fast) { const { slow_, fast_, ttfb_ } = this; if (slow_.halfLife !== slow) this.slow_ = new EWMA(slow, slow_.getEstimate(), slow_.getTotalWeight()); if (fast_.halfLife !== fast) this.fast_ = new EWMA(fast, fast_.getEstimate(), fast_.getTotalWeight()); if (ttfb_.halfLife !== slow) this.ttfb_ = new EWMA(slow, ttfb_.getEstimate(), ttfb_.getTotalWeight()); } sample(durationMs, numBytes) { durationMs = Math.max(durationMs, this.minDelayMs_); const numBits = 8 * numBytes; const durationS = durationMs / 1e3; const bandwidthInBps = numBits / durationS; this.fast_.sample(durationS, bandwidthInBps); this.slow_.sample(durationS, bandwidthInBps); } sampleTTFB(ttfb) { const seconds = ttfb / 1e3; const weight = Math.sqrt(2) * Math.exp(-Math.pow(seconds, 2) / 2); this.ttfb_.sample(weight, Math.max(ttfb, 5)); } canEstimate() { return this.fast_.getTotalWeight() >= this.minWeight_; } getEstimate() { if (this.canEstimate()) return Math.min(this.fast_.getEstimate(), this.slow_.getEstimate()); else return this.defaultEstimate_; } getEstimateTTFB() { if (this.ttfb_.getTotalWeight() >= this.minWeight_) return this.ttfb_.getEstimate(); else return this.defaultTTFB_; } get defaultEstimate() { return this.defaultEstimate_; } destroy() {} }; function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function(n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function(r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function(r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } var Logger = class { constructor(label, logger) { this.trace = void 0; this.debug = void 0; this.log = void 0; this.warn = void 0; this.info = void 0; this.error = void 0; const lb = `[${label}]:`; this.trace = noop; this.debug = logger.debug.bind(null, lb); this.log = logger.log.bind(null, lb); this.warn = logger.warn.bind(null, lb); this.info = logger.info.bind(null, lb); this.error = logger.error.bind(null, lb); } }; var noop = function noop() {}; var fakeLogger = { trace: noop, debug: noop, log: noop, warn: noop, info: noop, error: noop }; function createLogger() { return _extends({}, fakeLogger); } function consolePrintFn(type, id) { const func = self.console[type]; return func ? func.bind(self.console, `${id ? "[" + id + "] " : ""}[${type}] >`) : noop; } function getLoggerFn(key, debugConfig, id) { return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id); } var exportedLogger = createLogger(); function enableLogs(debugConfig, context, id) { const newLogger = createLogger(); if (typeof console === "object" && debugConfig === true || typeof debugConfig === "object") { const keys = [ "debug", "log", "info", "warn", "error" ]; keys.forEach((key) => { newLogger[key] = getLoggerFn(key, debugConfig, id); }); try { newLogger.log(`Debug logs enabled for "${context}" in hls.js version 1.6.16`); } catch (e) { return createLogger(); } keys.forEach((key) => { exportedLogger[key] = getLoggerFn(key, debugConfig); }); } else _extends(exportedLogger, newLogger); return newLogger; } var logger = exportedLogger; function getMediaSource(preferManagedMediaSource = true) { if (typeof self === "undefined") return void 0; return (preferManagedMediaSource || !self.MediaSource) && self.ManagedMediaSource || self.MediaSource || self.WebKitMediaSource; } function isManagedMediaSource(source) { return typeof self !== "undefined" && source === self.ManagedMediaSource; } function isCompatibleTrackChange(currentTracks, requiredTracks) { const trackNames = Object.keys(currentTracks); const requiredTrackNames = Object.keys(requiredTracks); const trackCount = trackNames.length; const requiredTrackCount = requiredTrackNames.length; return !trackCount || !requiredTrackCount || trackCount === requiredTrackCount && !trackNames.some((name) => requiredTrackNames.indexOf(name) === -1); } /** * Converts a UTF-8 array to a string. * * @param array - The UTF-8 array to convert * * @returns The string * * @group Utils * * @beta */ function utf8ArrayToStr(array, exitOnNull = false) { if (typeof TextDecoder !== "undefined") { const decoded = new TextDecoder("utf-8").decode(array); if (exitOnNull) { const idx = decoded.indexOf("\0"); return idx !== -1 ? decoded.substring(0, idx) : decoded; } return decoded.replace(/\0/g, ""); } const len = array.length; let c; let char2; let char3; let out = ""; let i = 0; while (i < len) { c = array[i++]; if (c === 0 && exitOnNull) return out; else if (c === 0 || c === 3) continue; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: out += String.fromCharCode(c); break; case 12: case 13: char2 = array[i++]; out += String.fromCharCode((c & 31) << 6 | char2 & 63); break; case 14: char2 = array[i++]; char3 = array[i++]; out += String.fromCharCode((c & 15) << 12 | (char2 & 63) << 6 | (char3 & 63) << 0); break; } } return out; } /** * hex dump helper class */ function arrayToHex(array) { let str = ""; for (let i = 0; i < array.length; i++) { let h = array[i].toString(16); if (h.length < 2) h = "0" + h; str += h; } return str; } function hexToArrayBuffer(str) { return Uint8Array.from(str.replace(/^0x/, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")).buffer; } function getDefaultExportFromCjs(x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; } var urlToolkit = { exports: {} }; var hasRequiredUrlToolkit; function requireUrlToolkit() { if (hasRequiredUrlToolkit) return urlToolkit.exports; hasRequiredUrlToolkit = 1; (function(module, exports) { (function(root) { var URL_REGEX = /^(?=((?:[a-zA-Z0-9+\-.]+:)?))\1(?=((?:\/\/[^\/?#]*)?))\2(?=((?:(?:[^?#\/]*\/)*[^;?#\/]*)?))\3((?:;[^?#]*)?)(\?[^#]*)?(#[^]*)?$/; var FIRST_SEGMENT_REGEX = /^(?=([^\/?#]*))\1([^]*)$/; var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g; var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g; var URLToolkit = { buildAbsoluteURL: function(baseURL, relativeURL, opts) { opts = opts || {}; baseURL = baseURL.trim(); relativeURL = relativeURL.trim(); if (!relativeURL) { if (!opts.alwaysNormalize) return baseURL; var basePartsForNormalise = URLToolkit.parseURL(baseURL); if (!basePartsForNormalise) throw new Error("Error trying to parse base URL."); basePartsForNormalise.path = URLToolkit.normalizePath(basePartsForNormalise.path); return URLToolkit.buildURLFromParts(basePartsForNormalise); } var relativeParts = URLToolkit.parseURL(relativeURL); if (!relativeParts) throw new Error("Error trying to parse relative URL."); if (relativeParts.scheme) { if (!opts.alwaysNormalize) return relativeURL; relativeParts.path = URLToolkit.normalizePath(relativeParts.path); return URLToolkit.buildURLFromParts(relativeParts); } var baseParts = URLToolkit.parseURL(baseURL); if (!baseParts) throw new Error("Error trying to parse base URL."); if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== "/") { var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path); baseParts.netLoc = pathParts[1]; baseParts.path = pathParts[2]; } if (baseParts.netLoc && !baseParts.path) baseParts.path = "/"; var builtParts = { scheme: baseParts.scheme, netLoc: relativeParts.netLoc, path: null, params: relativeParts.params, query: relativeParts.query, fragment: relativeParts.fragment }; if (!relativeParts.netLoc) { builtParts.netLoc = baseParts.netLoc; if (relativeParts.path[0] !== "/") if (!relativeParts.path) { builtParts.path = baseParts.path; if (!relativeParts.params) { builtParts.params = baseParts.params; if (!relativeParts.query) builtParts.query = baseParts.query; } } else { var baseURLPath = baseParts.path; var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf("/") + 1) + relativeParts.path; builtParts.path = URLToolkit.normalizePath(newPath); } } if (builtParts.path === null) builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path; return URLToolkit.buildURLFromParts(builtParts); }, parseURL: function(url) { var parts = URL_REGEX.exec(url); if (!parts) return null; return { scheme: parts[1] || "", netLoc: parts[2] || "", path: parts[3] || "", params: parts[4] || "", query: parts[5] || "", fragment: parts[6] || "" }; }, normalizePath: function(path) { path = path.split("").reverse().join("").replace(SLASH_DOT_REGEX, ""); while (path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, "")).length); return path.split("").reverse().join(""); }, buildURLFromParts: function(parts) { return parts.scheme + parts.netLoc + parts.path + parts.params + parts.query + parts.fragment; } }; module.exports = URLToolkit; })(); })(urlToolkit); return urlToolkit.exports; } var urlToolkitExports = requireUrlToolkit(); var LoadStats = class { constructor() { this.aborted = false; this.loaded = 0; this.retry = 0; this.total = 0; this.chunkCount = 0; this.bwEstimate = 0; this.loading = { start: 0, first: 0, end: 0 }; this.parsing = { start: 0, end: 0 }; this.buffering = { start: 0, first: 0, end: 0 }; } }; var ElementaryStreamTypes = { AUDIO: "audio", VIDEO: "video", AUDIOVIDEO: "audiovideo" }; var BaseSegment = class { constructor(base) { this._byteRange = null; this._url = null; this._stats = null; this._streams = null; this.base = void 0; this.relurl = void 0; if (typeof base === "string") base = { url: base }; this.base = base; makeEnumerable(this, "stats"); } setByteRange(value, previous) { const params = value.split("@", 2); let start; if (params.length === 1) start = (previous == null ? void 0 : previous.byteRangeEndOffset) || 0; else start = parseInt(params[1]); this._byteRange = [start, parseInt(params[0]) + start]; } get baseurl() { return this.base.url; } get byteRange() { if (this._byteRange === null) return []; return this._byteRange; } get byteRangeStartOffset() { return this.byteRange[0]; } get byteRangeEndOffset() { return this.byteRange[1]; } get elementaryStreams() { if (this._streams === null) this._streams = { [ElementaryStreamTypes.AUDIO]: null, [ElementaryStreamTypes.VIDEO]: null, [ElementaryStreamTypes.AUDIOVIDEO]: null }; return this._streams; } set elementaryStreams(value) { this._streams = value; } get hasStats() { return this._stats !== null; } get hasStreams() { return this._streams !== null; } get stats() { if (this._stats === null) this._stats = new LoadStats(); return this._stats; } set stats(value) { this._stats = value; } get url() { if (!this._url && this.baseurl && this.relurl) this._url = urlToolkitExports.buildAbsoluteURL(this.baseurl, this.relurl, { alwaysNormalize: true }); return this._url || ""; } set url(value) { this._url = value; } clearElementaryStreamInfo() { const { elementaryStreams } = this; elementaryStreams[ElementaryStreamTypes.AUDIO] = null; elementaryStreams[ElementaryStreamTypes.VIDEO] = null; elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO] = null; } }; function isMediaFragment(frag) { return frag.sn !== "initSegment"; } /** * Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}. */ var Fragment = class extends BaseSegment { constructor(type, base) { super(base); this._decryptdata = null; this._programDateTime = null; this._ref = null; this._bitrate = void 0; this.rawProgramDateTime = null; this.tagList = []; this.duration = 0; this.sn = 0; this.levelkeys = void 0; this.type = void 0; this.loader = null; this.keyLoader = null; this.level = -1; this.cc = 0; this.startPTS = void 0; this.endPTS = void 0; this.startDTS = void 0; this.endDTS = void 0; this.start = 0; this.playlistOffset = 0; this.deltaPTS = void 0; this.maxStartPTS = void 0; this.minEndPTS = void 0; this.data = void 0; this.bitrateTest = false; this.title = null; this.initSegment = null; this.endList = void 0; this.gap = void 0; this.urlId = 0; this.type = type; } get byteLength() { if (this.hasStats) { const total = this.stats.total; if (total) return total; } if (this.byteRange.length) { const start = this.byteRange[0]; const end = this.byteRange[1]; if (isFiniteNumber(start) && isFiniteNumber(end)) return end - start; } return null; } get bitrate() { if (this.byteLength) return this.byteLength * 8 / this.duration; if (this._bitrate) return this._bitrate; return null; } set bitrate(value) { this._bitrate = value; } get decryptdata() { var _this$_decryptdata; const { levelkeys } = this; if (!levelkeys || levelkeys.NONE) return null; if (levelkeys.identity) { if (!this._decryptdata) this._decryptdata = levelkeys.identity.getDecryptData(this.sn); } else if (!((_this$_decryptdata = this._decryptdata) != null && _this$_decryptdata.keyId)) { const keyFormats = Object.keys(levelkeys); if (keyFormats.length === 1) { const levelKey = this._decryptdata = levelkeys[keyFormats[0]] || null; if (levelKey) this._decryptdata = levelKey.getDecryptData(this.sn, levelkeys); } } return this._decryptdata; } get end() { return this.start + this.duration; } get endProgramDateTime() { if (this.programDateTime === null) return null; const duration = !isFiniteNumber(this.duration) ? 0 : this.duration; return this.programDateTime + duration * 1e3; } get encrypted() { var _this$_decryptdata2; if ((_this$_decryptdata2 = this._decryptdata) != null && _this$_decryptdata2.encrypted) return true; else if (this.levelkeys) { var _this$levelkeys$keyFo; const keyFormats = Object.keys(this.levelkeys); const len = keyFormats.length; if (len > 1 || len === 1 && (_this$levelkeys$keyFo = this.levelkeys[keyFormats[0]]) != null && _this$levelkeys$keyFo.encrypted) return true; } return false; } get programDateTime() { if (this._programDateTime === null && this.rawProgramDateTime) this.programDateTime = Date.parse(this.rawProgramDateTime); return this._programDateTime; } set programDateTime(value) { if (!isFiniteNumber(value)) { this._programDateTime = this.rawProgramDateTime = null; return; } this._programDateTime = value; } get ref() { if (!isMediaFragment(this)) return null; if (!this._ref) this._ref = { base: this.base, start: this.start, duration: this.duration, sn: this.sn, programDateTime: this.programDateTime }; return this._ref; } addStart(value) { this.setStart(this.start + value); } setStart(value) { this.start = value; if (this._ref) this._ref.start = value; } setDuration(value) { this.duration = value; if (this._ref) this._ref.duration = value; } setKeyFormat(keyFormat) { const levelkeys = this.levelkeys; if (levelkeys) { var _this$_decryptdata3; const key = levelkeys[keyFormat]; if (key && !((_this$_decryptdata3 = this._decryptdata) != null && _this$_decryptdata3.keyId)) this._decryptdata = key.getDecryptData(this.sn, levelkeys); } } abortRequests() { var _this$loader, _this$keyLoader; (_this$loader = this.loader) == null || _this$loader.abort(); (_this$keyLoader = this.keyLoader) == null || _this$keyLoader.abort(); } setElementaryStreamInfo(type, startPTS, endPTS, startDTS, endDTS, partial = false) { const { elementaryStreams } = this; const info = elementaryStreams[type]; if (!info) { elementaryStreams[type] = { startPTS, endPTS, startDTS, endDTS, partial }; return; } info.startPTS = Math.min(info.startPTS, startPTS); info.endPTS = Math.max(info.endPTS, endPTS); info.startDTS = Math.min(info.startDTS, startDTS); info.endDTS = Math.max(info.endDTS, endDTS); } }; /** * Object representing parsed data from an HLS Partial Segment. Found in {@link hls.js#LevelDetails.partList}. */ var Part = class extends BaseSegment { constructor(partAttrs, frag, base, index, previous) { super(base); this.fragOffset = 0; this.duration = 0; this.gap = false; this.independent = false; this.relurl = void 0; this.fragment = void 0; this.index = void 0; this.duration = partAttrs.decimalFloatingPoint("DURATION"); this.gap = partAttrs.bool("GAP"); this.independent = partAttrs.bool("INDEPENDENT"); this.relurl = partAttrs.enumeratedString("URI"); this.fragment = frag; this.index = index; const byteRange = partAttrs.enumeratedString("BYTERANGE"); if (byteRange) this.setByteRange(byteRange, previous); if (previous) this.fragOffset = previous.fragOffset + previous.duration; } get start() { return this.fragment.start + this.fragOffset; } get end() { return this.start + this.duration; } get loaded() { const { elementaryStreams } = this; return !!(elementaryStreams.audio || elementaryStreams.video || elementaryStreams.audiovideo); } }; function getOwnPropertyDescriptorFromPrototypeChain(object, property) { const prototype = Object.getPrototypeOf(object); if (prototype) { const propertyDescriptor = Object.getOwnPropertyDescriptor(prototype, property); if (propertyDescriptor) return propertyDescriptor; return getOwnPropertyDescriptorFromPrototypeChain(prototype, property); } } function makeEnumerable(object, property) { const d = getOwnPropertyDescriptorFromPrototypeChain(object, property); if (d) { d.enumerable = true; Object.defineProperty(object, property, d); } } var UINT32_MAX$1 = Math.pow(2, 32) - 1; var push = [].push; var RemuxerTrackIdConfig = { video: 1, audio: 2, id3: 3, text: 4 }; function bin2str(data) { return String.fromCharCode.apply(null, data); } function readUint16(buffer, offset) { const val = buffer[offset] << 8 | buffer[offset + 1]; return val < 0 ? 65536 + val : val; } function readUint32(buffer, offset) { const val = readSint32(buffer, offset); return val < 0 ? 4294967296 + val : val; } function readUint64(buffer, offset) { let result = readUint32(buffer, offset); result *= Math.pow(2, 32); result += readUint32(buffer, offset + 4); return result; } function readSint32(buffer, offset) { return buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3]; } function hasMoofData(data) { const end = data.byteLength; for (let i = 0; i < end;) { const size = readUint32(data, i); if (size > 8 && data[i + 4] === 109 && data[i + 5] === 111 && data[i + 6] === 111 && data[i + 7] === 102) return true; i = size > 1 ? i + size : end; } return false; } function findBox(data, path) { const results = []; if (!path.length) return results; const end = data.byteLength; for (let i = 0; i < end;) { const size = readUint32(data, i); const type = bin2str(data.subarray(i + 4, i + 8)); const endbox = size > 1 ? i + size : end; if (type === path[0]) if (path.length === 1) results.push(data.subarray(i + 8, endbox)); else { const subresults = findBox(data.subarray(i + 8, endbox), path.slice(1)); if (subresults.length) push.apply(results, subresults); } i = endbox; } return results; } function parseSegmentIndex(sidx) { const references = []; const version = sidx[0]; let index = 8; const timescale = readUint32(sidx, index); index += 4; let earliestPresentationTime = 0; let firstOffset = 0; if (version === 0) { earliestPresentationTime = readUint32(sidx, index); firstOffset = readUint32(sidx, index + 4); index += 8; } else { earliestPresentationTime = readUint64(sidx, index); firstOffset = readUint64(sidx, index + 8); index += 16; } index += 2; let startByte = sidx.length + firstOffset; const referencesCount = readUint16(sidx, index); index += 2; for (let i = 0; i < referencesCount; i++) { let referenceIndex = index; const referenceInfo = readUint32(sidx, referenceIndex); referenceIndex += 4; const referenceSize = referenceInfo & 2147483647; if ((referenceInfo & 2147483648) >>> 31 === 1) { logger.warn("SIDX has hierarchical references (not supported)"); return null; } const subsegmentDuration = readUint32(sidx, referenceIndex); referenceIndex += 4; references.push({ referenceSize, subsegmentDuration, info: { duration: subsegmentDuration / timescale, start: startByte, end: startByte + referenceSize - 1 } }); startByte += referenceSize; referenceIndex += 4; index = referenceIndex; } return { earliestPresentationTime, timescale, version, referencesCount, references }; } /** * Parses an MP4 initialization segment and extracts stream type and * timescale values for any declared tracks. Timescale values indicate the * number of clock ticks per second to assume for time-based values * elsewhere in the MP4. * * To determine the start time of an MP4, you need two pieces of * information: the timescale unit and the earliest base media decode * time. Multiple timescales can be specified within an MP4 but the * base media decode time is always expressed in the timescale from * the media header box for the track: * ``` * moov > trak > mdia > mdhd.timescale * moov > trak > mdia > hdlr * ``` * @param initSegment the bytes of the init segment * @returns a hash of track type to timescale values or null if * the init segment is malformed. */ function parseInitSegment(initSegment) { const result = []; const traks = findBox(initSegment, ["moov", "trak"]); for (let i = 0; i < traks.length; i++) { const trak = traks[i]; const tkhd = findBox(trak, ["tkhd"])[0]; if (tkhd) { let version = tkhd[0]; const trackId = readUint32(tkhd, version === 0 ? 12 : 20); const mdhd = findBox(trak, ["mdia", "mdhd"])[0]; if (mdhd) { version = mdhd[0]; const timescale = readUint32(mdhd, version === 0 ? 12 : 20); const hdlr = findBox(trak, ["mdia", "hdlr"])[0]; if (hdlr) { const hdlrType = bin2str(hdlr.subarray(8, 12)); const type = { soun: ElementaryStreamTypes.AUDIO, vide: ElementaryStreamTypes.VIDEO }[hdlrType]; const stsdBox = findBox(trak, [ "mdia", "minf", "stbl", "stsd" ])[0]; const stsd = parseStsd(stsdBox); if (type) { result[trackId] = { timescale, type, stsd }; result[type] = _objectSpread2({ timescale, id: trackId }, stsd); } else result[trackId] = { timescale, type: hdlrType, stsd }; } } } } findBox(initSegment, [ "moov", "mvex", "trex" ]).forEach((trex) => { const track = result[readUint32(trex, 4)]; if (track) track.default = { duration: readUint32(trex, 12), flags: readUint32(trex, 20) }; }); return result; } function parseStsd(stsd) { const sampleEntries = stsd.subarray(8); const sampleEntriesEnd = sampleEntries.subarray(86); const fourCC = bin2str(sampleEntries.subarray(4, 8)); let codec = fourCC; let supplemental; const encrypted = fourCC === "enca" || fourCC === "encv"; if (encrypted) findBox(findBox(sampleEntries, [fourCC])[0].subarray(fourCC === "enca" ? 28 : 78), ["sinf"]).forEach((sinf) => { const schm = findBox(sinf, ["schm"])[0]; if (schm) { const scheme = bin2str(schm.subarray(4, 8)); if (scheme === "cbcs" || scheme === "cenc") { const frma = findBox(sinf, ["frma"])[0]; if (frma) codec = bin2str(frma); } } }); const codecFourCC = codec; switch (codec) { case "avc1": case "avc2": case "avc3": case "avc4": { const avcCBox = findBox(sampleEntriesEnd, ["avcC"])[0]; if (avcCBox && avcCBox.length > 3) { codec += "." + toHex(avcCBox[1]) + toHex(avcCBox[2]) + toHex(avcCBox[3]); supplemental = parseSupplementalDoViCodec(codecFourCC === "avc1" ? "dva1" : "dvav", sampleEntriesEnd); } break; } case "mp4a": { const codecBox = findBox(sampleEntries, [fourCC])[0]; const esdsBox = findBox(codecBox.subarray(28), ["esds"])[0]; if (esdsBox && esdsBox.length > 7) { let i = 4; if (esdsBox[i++] !== 3) break; i = skipBERInteger(esdsBox, i); i += 2; const flags = esdsBox[i++]; if (flags & 128) i += 2; if (flags & 64) i += esdsBox[i++]; if (esdsBox[i++] !== 4) break; i = skipBERInteger(esdsBox, i); const objectType = esdsBox[i++]; if (objectType === 64) codec += "." + toHex(objectType); else break; i += 12; if (esdsBox[i++] !== 5) break; i = skipBERInteger(esdsBox, i); const firstByte = esdsBox[i++]; let audioObjectType = (firstByte & 248) >> 3; if (audioObjectType === 31) audioObjectType += 1 + ((firstByte & 7) << 3) + ((esdsBox[i] & 224) >> 5); codec += "." + audioObjectType; } break; } case "hvc1": case "hev1": { const hvcCBox = findBox(sampleEntriesEnd, ["hvcC"])[0]; if (hvcCBox && hvcCBox.length > 12) { const profileByte = hvcCBox[1]; const profileSpace = [ "", "A", "B", "C" ][profileByte >> 6]; const generalProfileIdc = profileByte & 31; const profileCompat = readUint32(hvcCBox, 2); const tierFlag = (profileByte & 32) >> 5 ? "H" : "L"; const levelIDC = hvcCBox[12]; const constraintIndicator = hvcCBox.subarray(6, 12); codec += "." + profileSpace + generalProfileIdc; codec += "." + reverse32BitInt(profileCompat).toString(16).toUpperCase(); codec += "." + tierFlag + levelIDC; let constraintString = ""; for (let i = constraintIndicator.length; i--;) { const byte = constraintIndicator[i]; if (byte || constraintString) constraintString = "." + byte.toString(16).toUpperCase() + constraintString; } codec += constraintString; } supplemental = parseSupplementalDoViCodec(codecFourCC == "hev1" ? "dvhe" : "dvh1", sampleEntriesEnd); break; } case "dvh1": case "dvhe": case "dvav": case "dva1": case "dav1": codec = parseSupplementalDoViCodec(codec, sampleEntriesEnd) || codec; break; case "vp09": { const vpcCBox = findBox(sampleEntriesEnd, ["vpcC"])[0]; if (vpcCBox && vpcCBox.length > 6) { const profile = vpcCBox[4]; const level = vpcCBox[5]; const bitDepth = vpcCBox[6] >> 4 & 15; codec += "." + addLeadingZero(profile) + "." + addLeadingZero(level) + "." + addLeadingZero(bitDepth); } break; } case "av01": { const av1CBox = findBox(sampleEntriesEnd, ["av1C"])[0]; if (av1CBox && av1CBox.length > 2) { const profile = av1CBox[1] >>> 5; const level = av1CBox[1] & 31; const tierFlag = av1CBox[2] >>> 7 ? "H" : "M"; const highBitDepth = (av1CBox[2] & 64) >> 6; const twelveBit = (av1CBox[2] & 32) >> 5; const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; const monochrome = (av1CBox[2] & 16) >> 4; const chromaSubsamplingX = (av1CBox[2] & 8) >> 3; const chromaSubsamplingY = (av1CBox[2] & 4) >> 2; const chromaSamplePosition = av1CBox[2] & 3; codec += "." + profile + "." + addLeadingZero(level) + tierFlag + "." + addLeadingZero(bitDepth) + "." + monochrome + "." + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition + "." + addLeadingZero(1) + "." + addLeadingZero(1) + "." + addLeadingZero(1) + ".0"; supplemental = parseSupplementalDoViCodec("dav1", sampleEntriesEnd); } break; } } return { codec, encrypted, supplemental }; } function parseSupplementalDoViCodec(fourCC, sampleEntriesEnd) { const dvvCResult = findBox(sampleEntriesEnd, ["dvvC"]); const dvXCBox = dvvCResult.length ? dvvCResult[0] : findBox(sampleEntriesEnd, ["dvcC"])[0]; if (dvXCBox) { const doViProfile = dvXCBox[2] >> 1 & 127; const doViLevel = dvXCBox[2] << 5 & 32 | dvXCBox[3] >> 3 & 31; return fourCC + "." + addLeadingZero(doViProfile) + "." + addLeadingZero(doViLevel); } } function reverse32BitInt(val) { let result = 0; for (let i = 0; i < 32; i++) result |= (val >> i & 1) << 31 - i; return result >>> 0; } function skipBERInteger(bytes, i) { const limit = i + 5; while (bytes[i++] & 128 && i < limit); return i; } function toHex(x) { return ("0" + x.toString(16).toUpperCase()).slice(-2); } function addLeadingZero(num) { return (num < 10 ? "0" : "") + num; } function patchEncyptionData(initSegment, decryptdata) { if (!initSegment || !decryptdata) return; const keyId = decryptdata.keyId; if (keyId && decryptdata.isCommonEncryption) applyToTencBoxes(initSegment, (tenc, isAudio) => { const tencKeyId = tenc.subarray(8, 24); if (!tencKeyId.some((b) => b !== 0)) { logger.log(`[eme] Patching keyId in 'enc${isAudio ? "a" : "v"}>sinf>>tenc' box: ${arrayToHex(tencKeyId)} -> ${arrayToHex(keyId)}`); tenc.set(keyId, 8); } }); } function parseKeyIdsFromTenc(initSegment) { const keyIds = []; applyToTencBoxes(initSegment, (tenc) => keyIds.push(tenc.subarray(8, 24))); return keyIds; } function applyToTencBoxes(initSegment, predicate) { findBox(initSegment, ["moov", "trak"]).forEach((trak) => { const stsd = findBox(trak, [ "mdia", "minf", "stbl", "stsd" ])[0]; if (!stsd) return; const sampleEntries = stsd.subarray(8); let encBoxes = findBox(sampleEntries, ["enca"]); const isAudio = encBoxes.length > 0; if (!isAudio) encBoxes = findBox(sampleEntries, ["encv"]); encBoxes.forEach((enc) => { findBox(isAudio ? enc.subarray(28) : enc.subarray(78), ["sinf"]).forEach((sinf) => { const tenc = parseSinf(sinf); if (tenc) predicate(tenc, isAudio); }); }); }); } function parseSinf(sinf) { const schm = findBox(sinf, ["schm"])[0]; if (schm) { const scheme = bin2str(schm.subarray(4, 8)); if (scheme === "cbcs" || scheme === "cenc") { const tenc = findBox(sinf, ["schi", "tenc"])[0]; if (tenc) return tenc; } } } function getSampleData(data, initData, logger) { const tracks = {}; const trafs = findBox(data, ["moof", "traf"]); for (let i = 0; i < trafs.length; i++) { const traf = trafs[i]; const tfhd = findBox(traf, ["tfhd"])[0]; const id = readUint32(tfhd, 4); const track = initData[id]; if (!track) continue; tracks[id] || (tracks[id] = { start: NaN, duration: 0, sampleCount: 0, timescale: track.timescale, type: track.type }); const trackTimes = tracks[id]; const tfdt = findBox(traf, ["tfdt"])[0]; if (tfdt) { const version = tfdt[0]; let baseTime = readUint32(tfdt, 4); if (version === 1) if (baseTime === UINT32_MAX$1) logger.warn(`[mp4-demuxer]: Ignoring assumed invalid signed 64-bit track fragment decode time`); else { baseTime *= UINT32_MAX$1 + 1; baseTime += readUint32(tfdt, 8); } if (isFiniteNumber(baseTime) && (!isFiniteNumber(trackTimes.start) || baseTime < trackTimes.start)) trackTimes.start = baseTime; } const trackDefault = track.default; const tfhdFlags = readUint32(tfhd, 0) | (trackDefault == null ? void 0 : trackDefault.flags); let defaultSampleDuration = (trackDefault == null ? void 0 : trackDefault.duration) || 0; if (tfhdFlags & 8) if (tfhdFlags & 2) defaultSampleDuration = readUint32(tfhd, 12); else defaultSampleDuration = readUint32(tfhd, 8); const truns = findBox(traf, ["trun"]); let sampleDTS = trackTimes.start || 0; let rawDuration = 0; let sampleDuration = defaultSampleDuration; for (let j = 0; j < truns.length; j++) { const trun = truns[j]; const sampleCount = readUint32(trun, 4); const sampleIndex = trackTimes.sampleCount; trackTimes.sampleCount += sampleCount; const dataOffsetPresent = trun[3] & 1; const firstSampleFlagsPresent = trun[3] & 4; const sampleDurationPresent = trun[2] & 1; const sampleSizePresent = trun[2] & 2; const sampleFlagsPresent = trun[2] & 4; const sampleCompositionTimeOffsetPresent = trun[2] & 8; let offset = 8; let remaining = sampleCount; if (dataOffsetPresent) offset += 4; if (firstSampleFlagsPresent && sampleCount) { if (!(trun[offset + 1] & 1) && trackTimes.keyFrameIndex === void 0) trackTimes.keyFrameIndex = sampleIndex; offset += 4; if (sampleDurationPresent) { sampleDuration = readUint32(trun, offset); offset += 4; } else sampleDuration = defaultSampleDuration; if (sampleSizePresent) offset += 4; if (sampleCompositionTimeOffsetPresent) offset += 4; sampleDTS += sampleDuration; rawDuration += sampleDuration; remaining--; } while (remaining--) { if (sampleDurationPresent) { sampleDuration = readUint32(trun, offset); offset += 4; } else sampleDuration = defaultSampleDuration; if (sampleSizePresent) offset += 4; if (sampleFlagsPresent) { if (!(trun[offset + 1] & 1)) { if (trackTimes.keyFrameIndex === void 0) { trackTimes.keyFrameIndex = trackTimes.sampleCount - (remaining + 1); trackTimes.keyFrameStart = sampleDTS; } } offset += 4; } if (sampleCompositionTimeOffsetPresent) offset += 4; sampleDTS += sampleDuration; rawDuration += sampleDuration; } if (!rawDuration && defaultSampleDuration) rawDuration += defaultSampleDuration * sampleCount; } trackTimes.duration += rawDuration; } if (!Object.keys(tracks).some((trackId) => tracks[trackId].duration)) { let sidxMinStart = Infinity; let sidxMaxEnd = 0; const sidxs = findBox(data, ["sidx"]); for (let i = 0; i < sidxs.length; i++) { const sidx = parseSegmentIndex(sidxs[i]); if (sidx != null && sidx.references) { sidxMinStart = Math.min(sidxMinStart, sidx.earliestPresentationTime / sidx.timescale); const subSegmentDuration = sidx.references.reduce((dur, ref) => dur + ref.info.duration || 0, 0); sidxMaxEnd = Math.max(sidxMaxEnd, subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale); } } if (sidxMaxEnd && isFiniteNumber(sidxMaxEnd)) Object.keys(tracks).forEach((trackId) => { if (!tracks[trackId].duration) tracks[trackId].duration = sidxMaxEnd * tracks[trackId].timescale - tracks[trackId].start; }); } return tracks; } function segmentValidRange(data) { const segmentedRange = { valid: null, remainder: null }; const moofs = findBox(data, ["moof"]); if (moofs.length < 2) { segmentedRange.remainder = data; return segmentedRange; } const last = moofs[moofs.length - 1]; segmentedRange.valid = data.slice(0, last.byteOffset - 8); segmentedRange.remainder = data.slice(last.byteOffset - 8); return segmentedRange; } function appendUint8Array(data1, data2) { const temp = new Uint8Array(data1.length + data2.length); temp.set(data1); temp.set(data2, data1.length); return temp; } function parseSamples(timeOffset, track) { const seiSamples = []; const videoData = track.samples; const timescale = track.timescale; const trackId = track.id; let isHEVCFlavor = false; findBox(videoData, ["moof"]).map((moof) => { const moofOffset = moof.byteOffset - 8; findBox(moof, ["traf"]).map((traf) => { const baseTime = findBox(traf, ["tfdt"]).map((tfdt) => { const version = tfdt[0]; let result = readUint32(tfdt, 4); if (version === 1) { result *= Math.pow(2, 32); result += readUint32(tfdt, 8); } return result / timescale; })[0]; if (baseTime !== void 0) timeOffset = baseTime; return findBox(traf, ["tfhd"]).map((tfhd) => { const id = readUint32(tfhd, 4); const tfhdFlags = readUint32(tfhd, 0) & 16777215; const baseDataOffsetPresent = (tfhdFlags & 1) !== 0; const sampleDescriptionIndexPresent = (tfhdFlags & 2) !== 0; const defaultSampleDurationPresent = (tfhdFlags & 8) !== 0; let defaultSampleDuration = 0; const defaultSampleSizePresent = (tfhdFlags & 16) !== 0; let defaultSampleSize = 0; const defaultSampleFlagsPresent = (tfhdFlags & 32) !== 0; let tfhdOffset = 8; if (id === trackId) { if (baseDataOffsetPresent) tfhdOffset += 8; if (sampleDescriptionIndexPresent) tfhdOffset += 4; if (defaultSampleDurationPresent) { defaultSampleDuration = readUint32(tfhd, tfhdOffset); tfhdOffset += 4; } if (defaultSampleSizePresent) { defaultSampleSize = readUint32(tfhd, tfhdOffset); tfhdOffset += 4; } if (defaultSampleFlagsPresent) tfhdOffset += 4; if (track.type === "video") isHEVCFlavor = isHEVC(track.codec); findBox(traf, ["trun"]).map((trun) => { const version = trun[0]; const flags = readUint32(trun, 0) & 16777215; const dataOffsetPresent = (flags & 1) !== 0; let dataOffset = 0; const firstSampleFlagsPresent = (flags & 4) !== 0; const sampleDurationPresent = (flags & 256) !== 0; let sampleDuration = 0; const sampleSizePresent = (flags & 512) !== 0; let sampleSize = 0; const sampleFlagsPresent = (flags & 1024) !== 0; const sampleCompositionOffsetsPresent = (flags & 2048) !== 0; let compositionOffset = 0; const sampleCount = readUint32(trun, 4); let trunOffset = 8; if (dataOffsetPresent) { dataOffset = readUint32(trun, trunOffset); trunOffset += 4; } if (firstSampleFlagsPresent) trunOffset += 4; let sampleOffset = dataOffset + moofOffset; for (let ix = 0; ix < sampleCount; ix++) { if (sampleDurationPresent) { sampleDuration = readUint32(trun, trunOffset); trunOffset += 4; } else sampleDuration = defaultSampleDuration; if (sampleSizePresent) { sampleSize = readUint32(trun, trunOffset); trunOffset += 4; } else sampleSize = defaultSampleSize; if (sampleFlagsPresent) trunOffset += 4; if (sampleCompositionOffsetsPresent) { if (version === 0) compositionOffset = readUint32(trun, trunOffset); else compositionOffset = readSint32(trun, trunOffset); trunOffset += 4; } if (track.type === ElementaryStreamTypes.VIDEO) { let naluTotalSize = 0; while (naluTotalSize < sampleSize) { const naluSize = readUint32(videoData, sampleOffset); sampleOffset += 4; if (isSEIMessage(isHEVCFlavor, videoData[sampleOffset])) parseSEIMessageFromNALu(videoData.subarray(sampleOffset, sampleOffset + naluSize), isHEVCFlavor ? 2 : 1, timeOffset + compositionOffset / timescale, seiSamples); sampleOffset += naluSize; naluTotalSize += naluSize + 4; } } timeOffset += sampleDuration / timescale; } }); } }); }); }); return seiSamples; } function isHEVC(codec) { if (!codec) return false; const baseCodec = codec.substring(0, 4); return baseCodec === "hvc1" || baseCodec === "hev1" || baseCodec === "dvh1" || baseCodec === "dvhe"; } function isSEIMessage(isHEVCFlavor, naluHeader) { if (isHEVCFlavor) { const naluType = naluHeader >> 1 & 63; return naluType === 39 || naluType === 40; } else return (naluHeader & 31) === 6; } function parseSEIMessageFromNALu(unescapedData, headerSize, pts, samples) { const data = discardEPB(unescapedData); let seiPtr = 0; seiPtr += headerSize; let payloadType = 0; let payloadSize = 0; let b = 0; while (seiPtr < data.length) { payloadType = 0; do { if (seiPtr >= data.length) break; b = data[seiPtr++]; payloadType += b; } while (b === 255); payloadSize = 0; do { if (seiPtr >= data.length) break; b = data[seiPtr++]; payloadSize += b; } while (b === 255); const leftOver = data.length - seiPtr; let payPtr = seiPtr; if (payloadSize < leftOver) seiPtr += payloadSize; else if (payloadSize > leftOver) { logger.error(`Malformed SEI payload. ${payloadSize} is too small, only ${leftOver} bytes left to parse.`); break; } if (payloadType === 4) { if (data[payPtr++] === 181) { const providerCode = readUint16(data, payPtr); payPtr += 2; if (providerCode === 49) { const userStructure = readUint32(data, payPtr); payPtr += 4; if (userStructure === 1195456820) { const userDataType = data[payPtr++]; if (userDataType === 3) { const firstByte = data[payPtr++]; const totalCCs = 31 & firstByte; const enabled = 64 & firstByte; const totalBytes = enabled ? 2 + totalCCs * 3 : 0; const byteArray = new Uint8Array(totalBytes); if (enabled) { byteArray[0] = firstByte; for (let i = 1; i < totalBytes; i++) byteArray[i] = data[payPtr++]; } samples.push({ type: userDataType, payloadType, pts, bytes: byteArray }); } } } } } else if (payloadType === 5) { if (payloadSize > 16) { const uuidStrArray = []; for (let i = 0; i < 16; i++) { const _b = data[payPtr++].toString(16); uuidStrArray.push(_b.length == 1 ? "0" + _b : _b); if (i === 3 || i === 5 || i === 7 || i === 9) uuidStrArray.push("-"); } const length = payloadSize - 16; const userDataBytes = new Uint8Array(length); for (let i = 0; i < length; i++) userDataBytes[i] = data[payPtr++]; samples.push({ payloadType, pts, uuid: uuidStrArray.join(""), userData: utf8ArrayToStr(userDataBytes), userDataBytes }); } } } } /** * remove Emulation Prevention bytes from a RBSP */ function discardEPB(data) { const length = data.byteLength; const EPBPositions = []; let i = 1; while (i < length - 2) if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 3) { EPBPositions.push(i + 2); i += 2; } else i++; if (EPBPositions.length === 0) return data; const newLength = length - EPBPositions.length; const newData = new Uint8Array(newLength); let sourceIndex = 0; for (i = 0; i < newLength; sourceIndex++, i++) { if (sourceIndex === EPBPositions[0]) { sourceIndex++; EPBPositions.shift(); } newData[i] = data[sourceIndex]; } return newData; } function parseEmsg(data) { const version = data[0]; let schemeIdUri = ""; let value = ""; let timeScale = 0; let presentationTimeDelta = 0; let presentationTime = 0; let eventDuration = 0; let id = 0; let offset = 0; if (version === 0) { while (bin2str(data.subarray(offset, offset + 1)) !== "\0") { schemeIdUri += bin2str(data.subarray(offset, offset + 1)); offset += 1; } schemeIdUri += bin2str(data.subarray(offset, offset + 1)); offset += 1; while (bin2str(data.subarray(offset, offset + 1)) !== "\0") { value += bin2str(data.subarray(offset, offset + 1)); offset += 1; } value += bin2str(data.subarray(offset, offset + 1)); offset += 1; timeScale = readUint32(data, 12); presentationTimeDelta = readUint32(data, 16); eventDuration = readUint32(data, 20); id = readUint32(data, 24); offset = 28; } else if (version === 1) { offset += 4; timeScale = readUint32(data, offset); offset += 4; const leftPresentationTime = readUint32(data, offset); offset += 4; const rightPresentationTime = readUint32(data, offset); offset += 4; presentationTime = 2 ** 32 * leftPresentationTime + rightPresentationTime; if (!isSafeInteger(presentationTime)) { presentationTime = Number.MAX_SAFE_INTEGER; logger.warn("Presentation time exceeds safe integer limit and wrapped to max safe integer in parsing emsg box"); } eventDuration = readUint32(data, offset); offset += 4; id = readUint32(data, offset); offset += 4; while (bin2str(data.subarray(offset, offset + 1)) !== "\0") { schemeIdUri += bin2str(data.subarray(offset, offset + 1)); offset += 1; } schemeIdUri += bin2str(data.subarray(offset, offset + 1)); offset += 1; while (bin2str(data.subarray(offset, offset + 1)) !== "\0") { value += bin2str(data.subarray(offset, offset + 1)); offset += 1; } value += bin2str(data.subarray(offset, offset + 1)); offset += 1; } const payload = data.subarray(offset, data.byteLength); return { schemeIdUri, value, timeScale, presentationTime, presentationTimeDelta, eventDuration, id, payload }; } function mp4Box(type, ...payload) { const len = payload.length; let size = 8; let i = len; while (i--) size += payload[i].byteLength; const result = new Uint8Array(size); result[0] = size >> 24 & 255; result[1] = size >> 16 & 255; result[2] = size >> 8 & 255; result[3] = size & 255; result.set(type, 4); for (i = 0, size = 8; i < len; i++) { result.set(payload[i], size); size += payload[i].byteLength; } return result; } function mp4pssh(systemId, keyids, data) { if (systemId.byteLength !== 16) throw new RangeError("Invalid system id"); let version; let kids; version = 0; kids = new Uint8Array(); let kidCount; if (version > 0) { kidCount = new Uint8Array(4); if (keyids.length > 0) new DataView(kidCount.buffer).setUint32(0, keyids.length, false); } else kidCount = new Uint8Array(); const dataSize = new Uint8Array(4); if (data.byteLength > 0) new DataView(dataSize.buffer).setUint32(0, data.byteLength, false); return mp4Box([ 112, 115, 115, 104 ], new Uint8Array([ version, 0, 0, 0 ]), systemId, kidCount, kids, dataSize, data); } function parseMultiPssh(initData) { const results = []; if (initData instanceof ArrayBuffer) { const length = initData.byteLength; let offset = 0; while (offset + 32 < length) { const pssh = parsePssh(new DataView(initData, offset)); results.push(pssh); offset += pssh.size; } } return results; } function parsePssh(view) { const size = view.getUint32(0); const offset = view.byteOffset; const length = view.byteLength; if (length < size) return { offset, size: length }; if (view.getUint32(4) !== 1886614376) return { offset, size }; const version = view.getUint32(8) >>> 24; if (version !== 0 && version !== 1) return { offset, size }; const buffer = view.buffer; const systemId = arrayToHex(new Uint8Array(buffer, offset + 12, 16)); let kids = null; let data = null; let dataSizeOffset = 0; if (version === 0) dataSizeOffset = 28; else { const kidCounts = view.getUint32(28); if (!kidCounts || length < 32 + kidCounts * 16) return { offset, size }; kids = []; for (let i = 0; i < kidCounts; i++) kids.push(new Uint8Array(buffer, offset + 32 + i * 16, 16)); dataSizeOffset = 32 + kidCounts * 16; } if (!dataSizeOffset) return { offset, size }; const dataSizeOrKidCount = view.getUint32(dataSizeOffset); if (size - 32 < dataSizeOrKidCount) return { offset, size }; data = new Uint8Array(buffer, offset + dataSizeOffset + 4, dataSizeOrKidCount); return { version, systemId, kids, data, offset, size }; } var userAgentHevcSupportIsInaccurate = () => { return /\(Windows.+Firefox\//i.test(navigator.userAgent); }; var sampleEntryCodesISO = { audio: { a3ds: 1, "ac-3": .95, "ac-4": 1, alac: .9, alaw: 1, dra1: 1, "dts+": 1, "dts-": 1, dtsc: 1, dtse: 1, dtsh: 1, "ec-3": .9, enca: 1, fLaC: .9, flac: .9, FLAC: .9, g719: 1, g726: 1, m4ae: 1, mha1: 1, mha2: 1, mhm1: 1, mhm2: 1, mlpa: 1, mp4a: 1, "raw ": 1, Opus: 1, opus: 1, samr: 1, sawb: 1, sawp: 1, sevc: 1, sqcp: 1, ssmv: 1, twos: 1, ulaw: 1 }, video: { avc1: 1, avc2: 1, avc3: 1, avc4: 1, avcp: 1, av01: .8, dav1: .8, drac: 1, dva1: 1, dvav: 1, dvh1: .7, dvhe: .7, encv: 1, hev1: .75, hvc1: .75, mjp2: 1, mp4v: 1, mvc1: 1, mvc2: 1, mvc3: 1, mvc4: 1, resv: 1, rv60: 1, s263: 1, svc1: 1, svc2: 1, "vc-1": 1, vp08: 1, vp09: .9 }, text: { stpp: 1, wvtt: 1 } }; function isCodecType(codec, type) { const typeCodes = sampleEntryCodesISO[type]; return !!typeCodes && !!typeCodes[codec.slice(0, 4)]; } function areCodecsMediaSourceSupported(codecs, type, preferManagedMediaSource = true) { return !codecs.split(",").some((codec) => !isCodecMediaSourceSupported(codec, type, preferManagedMediaSource)); } function isCodecMediaSourceSupported(codec, type, preferManagedMediaSource = true) { var _MediaSource$isTypeSu; const MediaSource = getMediaSource(preferManagedMediaSource); return (_MediaSource$isTypeSu = MediaSource == null ? void 0 : MediaSource.isTypeSupported(mimeTypeForCodec(codec, type))) != null ? _MediaSource$isTypeSu : false; } function mimeTypeForCodec(codec, type) { return `${type}/mp4;codecs=${codec}`; } function videoCodecPreferenceValue(videoCodec) { if (videoCodec) { const fourCC = videoCodec.substring(0, 4); return sampleEntryCodesISO.video[fourCC]; } return 2; } function codecsSetSelectionPreferenceValue(codecSet) { const limitedHevcSupport = userAgentHevcSupportIsInaccurate(); return codecSet.split(",").reduce((num, fourCC) => { const preferenceValue = limitedHevcSupport && isHEVC(fourCC) ? 9 : sampleEntryCodesISO.video[fourCC]; if (preferenceValue) return (preferenceValue * 2 + num) / (num ? 3 : 2); return (sampleEntryCodesISO.audio[fourCC] + num) / (num ? 2 : 1); }, 0); } var CODEC_COMPATIBLE_NAMES = {}; function getCodecCompatibleNameLower(lowerCaseCodec, preferManagedMediaSource = true) { if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) return CODEC_COMPATIBLE_NAMES[lowerCaseCodec]; const codecsToCheck = { flac: [ "flac", "fLaC", "FLAC" ], opus: ["opus", "Opus"], "mp4a.40.34": ["mp3"] }[lowerCaseCodec]; for (let i = 0; i < codecsToCheck.length; i++) { var _getMediaSource; if (isCodecMediaSourceSupported(codecsToCheck[i], "audio", preferManagedMediaSource)) { CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i]; return codecsToCheck[i]; } else if (codecsToCheck[i] === "mp3" && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported("audio/mpeg")) return ""; } return lowerCaseCodec; } var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i; function getCodecCompatibleName(codec, preferManagedMediaSource = true) { return codec.replace(AUDIO_CODEC_REGEXP, (m) => getCodecCompatibleNameLower(m.toLowerCase(), preferManagedMediaSource)); } function replaceVideoCodec(originalCodecs, newVideoCodec) { const codecs = []; if (originalCodecs) { const allCodecs = originalCodecs.split(","); for (let i = 0; i < allCodecs.length; i++) if (!isCodecType(allCodecs[i], "video")) codecs.push(allCodecs[i]); } if (newVideoCodec) codecs.push(newVideoCodec); return codecs.join(","); } function pickMostCompleteCodecName(parsedCodec, levelCodec) { if (parsedCodec && (parsedCodec.length > 4 || [ "ac-3", "ec-3", "alac", "fLaC", "Opus" ].indexOf(parsedCodec) !== -1)) { if (isCodecSupportedAsType(parsedCodec, "audio") || isCodecSupportedAsType(parsedCodec, "video")) return parsedCodec; } if (levelCodec) { const levelCodecs = levelCodec.split(","); if (levelCodecs.length > 1) { if (parsedCodec) { for (let i = levelCodecs.length; i--;) if (levelCodecs[i].substring(0, 4) === parsedCodec.substring(0, 4)) return levelCodecs[i]; } return levelCodecs[0]; } } return levelCodec || parsedCodec; } function isCodecSupportedAsType(codec, type) { return isCodecType(codec, type) && isCodecMediaSourceSupported(codec, type); } function convertAVC1ToAVCOTI(videoCodecs) { const codecs = videoCodecs.split(","); for (let i = 0; i < codecs.length; i++) { const avcdata = codecs[i].split("."); if (avcdata.length > 2 && avcdata[0] === "avc1") codecs[i] = `avc1.${parseInt(avcdata[1]).toString(16)}${("000" + parseInt(avcdata[2]).toString(16)).slice(-4)}`; } return codecs.join(","); } function fillInMissingAV01Params(videoCodec) { if (videoCodec.startsWith("av01.")) { const av1params = videoCodec.split("."); const placeholders = [ "0", "111", "01", "01", "01", "0" ]; for (let i = av1params.length; i > 4 && i < 10; i++) av1params[i] = placeholders[i - 4]; return av1params.join("."); } return videoCodec; } function getM2TSSupportedAudioTypes(preferManagedMediaSource) { const MediaSource = getMediaSource(preferManagedMediaSource) || { isTypeSupported: () => false }; return { mpeg: MediaSource.isTypeSupported("audio/mpeg"), mp3: MediaSource.isTypeSupported("audio/mp4; codecs=\"mp3\""), ac3: MediaSource.isTypeSupported("audio/mp4; codecs=\"ac-3\"") }; } function getCodecsForMimeType(mimeType) { return mimeType.replace(/^.+codecs=["']?([^"']+).*$/, "$1"); } var supportedResult = { supported: true, powerEfficient: true, smooth: true }; var unsupportedResult = { supported: false, smooth: false, powerEfficient: false }; var SUPPORTED_INFO_DEFAULT = { supported: true, configurations: [], decodingInfoResults: [supportedResult] }; function getUnsupportedResult(error, configurations) { return { supported: false, configurations, decodingInfoResults: [unsupportedResult], error }; } function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference) { const videoCodecs = level.videoCodec; const audioGroups = level.audioCodec ? level.audioGroups : null; const audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec; const channelsPreference = audioPreference == null ? void 0 : audioPreference.channels; const maxChannels = channelsPreference ? parseInt(channelsPreference) : audioCodecPreference ? Infinity : 2; let audioChannels = null; if (audioGroups != null && audioGroups.length) try { if (audioGroups.length === 1 && audioGroups[0]) audioChannels = audioTracksByGroup.groups[audioGroups[0]].channels; else audioChannels = audioGroups.reduce((acc, groupId) => { if (groupId) { const audioTrackGroup = audioTracksByGroup.groups[groupId]; if (!audioTrackGroup) throw new Error(`Audio track group ${groupId} not found`); Object.keys(audioTrackGroup.channels).forEach((key) => { acc[key] = (acc[key] || 0) + audioTrackGroup.channels[key]; }); } return acc; }, { 2: 0 }); } catch (error) { return true; } return videoCodecs !== void 0 && (videoCodecs.split(",").some((videoCodec) => isHEVC(videoCodec)) || level.width > 1920 && level.height > 1088 || level.height > 1920 && level.width > 1088 || level.frameRate > Math.max(currentFrameRate, 30) || level.videoRange !== "SDR" && level.videoRange !== currentVideoRange || level.bitrate > Math.max(currentBw, 8e6)) || !!audioChannels && isFiniteNumber(maxChannels) && Object.keys(audioChannels).some((channels) => parseInt(channels) > maxChannels); } function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities, cache = {}) { const videoCodecs = level.videoCodec; if (!videoCodecs && !level.audioCodec || !mediaCapabilities) return Promise.resolve(SUPPORTED_INFO_DEFAULT); const configurations = []; const videoDecodeList = makeVideoConfigurations(level); const videoCount = videoDecodeList.length; const audioDecodeList = makeAudioConfigurations(level, audioTracksByGroup, videoCount > 0); const audioCount = audioDecodeList.length; for (let i = videoCount || 1 * audioCount || 1; i--;) { const configuration = { type: "media-source" }; if (videoCount) configuration.video = videoDecodeList[i % videoCount]; if (audioCount) { configuration.audio = audioDecodeList[i % audioCount]; const audioBitrate = configuration.audio.bitrate; if (configuration.video && audioBitrate) configuration.video.bitrate -= audioBitrate; } configurations.push(configuration); } if (videoCodecs) { const ua = navigator.userAgent; if (videoCodecs.split(",").some((videoCodec) => isHEVC(videoCodec)) && userAgentHevcSupportIsInaccurate()) return Promise.resolve(getUnsupportedResult(/* @__PURE__ */ new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent string: (${ua})`), configurations)); } return Promise.all(configurations.map((configuration) => { const decodingInfoKey = getMediaDecodingInfoKey(configuration); return cache[decodingInfoKey] || (cache[decodingInfoKey] = mediaCapabilities.decodingInfo(configuration)); })).then((decodingInfoResults) => ({ supported: !decodingInfoResults.some((info) => !info.supported), configurations, decodingInfoResults })).catch((error) => ({ supported: false, configurations, decodingInfoResults: [], error })); } function makeVideoConfigurations(level) { var _level$videoCodec; const videoCodecs = (_level$videoCodec = level.videoCodec) == null ? void 0 : _level$videoCodec.split(","); const bitrate = getVariantDecodingBitrate(level); const width = level.width || 640; const height = level.height || 480; const framerate = level.frameRate || 30; const videoRange = level.videoRange.toLowerCase(); return videoCodecs ? videoCodecs.map((videoCodec) => { const videoConfiguration = { contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), "video"), width, height, bitrate, framerate }; if (videoRange !== "sdr") videoConfiguration.transferFunction = videoRange; return videoConfiguration; }) : []; } function makeAudioConfigurations(level, audioTracksByGroup, hasVideo) { var _level$audioCodec; const audioCodecs = (_level$audioCodec = level.audioCodec) == null ? void 0 : _level$audioCodec.split(","); const combinedBitrate = getVariantDecodingBitrate(level); if (audioCodecs && level.audioGroups) return level.audioGroups.reduce((configurations, audioGroupId) => { var _audioTracksByGroup$g; const tracks = audioGroupId ? (_audioTracksByGroup$g = audioTracksByGroup.groups[audioGroupId]) == null ? void 0 : _audioTracksByGroup$g.tracks : null; if (tracks) return tracks.reduce((configs, audioTrack) => { if (audioTrack.groupId === audioGroupId) { const channelsNumber = parseFloat(audioTrack.channels || ""); audioCodecs.forEach((audioCodec) => { const audioConfiguration = { contentType: mimeTypeForCodec(audioCodec, "audio"), bitrate: hasVideo ? estimatedAudioBitrate(audioCodec, combinedBitrate) : combinedBitrate }; if (channelsNumber) audioConfiguration.channels = "" + channelsNumber; configs.push(audioConfiguration); }); } return configs; }, configurations); return configurations; }, []); return []; } function estimatedAudioBitrate(audioCodec, levelBitrate) { if (levelBitrate <= 1) return 1; let audioBitrate = 128e3; if (audioCodec === "ec-3") audioBitrate = 768e3; else if (audioCodec === "ac-3") audioBitrate = 64e4; return Math.min(levelBitrate / 2, audioBitrate); } function getVariantDecodingBitrate(level) { return Math.ceil(Math.max(level.bitrate * .9, level.averageBitrate) / 1e3) * 1e3 || 1; } function getMediaDecodingInfoKey(config) { let key = ""; const { audio, video } = config; if (video) { const codec = getCodecsForMimeType(video.contentType); key += `${codec}_r${video.height}x${video.width}f${Math.ceil(video.framerate)}${video.transferFunction || "sd"}_${Math.ceil(video.bitrate / 1e5)}`; } if (audio) { const codec = getCodecsForMimeType(audio.contentType); key += `${video ? "_" : ""}${codec}_c${audio.channels}`; } return key; } var HdcpLevels = [ "NONE", "TYPE-0", "TYPE-1", null ]; function isHdcpLevel(value) { return HdcpLevels.indexOf(value) > -1; } var VideoRangeValues = [ "SDR", "PQ", "HLG" ]; function isVideoRange(value) { return !!value && VideoRangeValues.indexOf(value) > -1; } var HlsSkip = { No: "", Yes: "YES", v2: "v2" }; function getSkipValue(details) { const { canSkipUntil, canSkipDateRanges, age } = details; const playlistRecentEnough = age < canSkipUntil / 2; if (canSkipUntil && playlistRecentEnough) { if (canSkipDateRanges) return HlsSkip.v2; return HlsSkip.Yes; } return HlsSkip.No; } var HlsUrlParameters = class { constructor(msn, part, skip) { this.msn = void 0; this.part = void 0; this.skip = void 0; this.msn = msn; this.part = part; this.skip = skip; } addDirectives(uri) { const url = new self.URL(uri); if (this.msn !== void 0) url.searchParams.set("_HLS_msn", this.msn.toString()); if (this.part !== void 0) url.searchParams.set("_HLS_part", this.part.toString()); if (this.skip) url.searchParams.set("_HLS_skip", this.skip); return url.href; } }; var Level = class { constructor(data) { this._attrs = void 0; this.audioCodec = void 0; this.bitrate = void 0; this.codecSet = void 0; this.url = void 0; this.frameRate = void 0; this.height = void 0; this.id = void 0; this.name = void 0; this.supplemental = void 0; this.videoCodec = void 0; this.width = void 0; this.details = void 0; this.fragmentError = 0; this.loadError = 0; this.loaded = void 0; this.realBitrate = 0; this.supportedPromise = void 0; this.supportedResult = void 0; this._avgBitrate = 0; this._audioGroups = void 0; this._subtitleGroups = void 0; this._urlId = 0; this.url = [data.url]; this._attrs = [data.attrs]; this.bitrate = data.bitrate; if (data.details) this.details = data.details; this.id = data.id || 0; this.name = data.name; this.width = data.width || 0; this.height = data.height || 0; this.frameRate = data.attrs.optionalFloat("FRAME-RATE", 0); this._avgBitrate = data.attrs.decimalInteger("AVERAGE-BANDWIDTH"); this.audioCodec = data.audioCodec; this.videoCodec = data.videoCodec; this.codecSet = [data.videoCodec, data.audioCodec].filter((c) => !!c).map((s) => s.substring(0, 4)).join(","); if ("supplemental" in data) { var _data$supplemental; this.supplemental = data.supplemental; const supplementalVideo = (_data$supplemental = data.supplemental) == null ? void 0 : _data$supplemental.videoCodec; if (supplementalVideo && supplementalVideo !== data.videoCodec) this.codecSet += `,${supplementalVideo.substring(0, 4)}`; } this.addGroupId("audio", data.attrs.AUDIO); this.addGroupId("text", data.attrs.SUBTITLES); } get maxBitrate() { return Math.max(this.realBitrate, this.bitrate); } get averageBitrate() { return this._avgBitrate || this.realBitrate || this.bitrate; } get attrs() { return this._attrs[0]; } get codecs() { return this.attrs.CODECS || ""; } get pathwayId() { return this.attrs["PATHWAY-ID"] || "."; } get videoRange() { return this.attrs["VIDEO-RANGE"] || "SDR"; } get score() { return this.attrs.optionalFloat("SCORE", 0); } get uri() { return this.url[0] || ""; } hasAudioGroup(groupId) { return hasGroup(this._audioGroups, groupId); } hasSubtitleGroup(groupId) { return hasGroup(this._subtitleGroups, groupId); } get audioGroups() { return this._audioGroups; } get subtitleGroups() { return this._subtitleGroups; } addGroupId(type, groupId) { if (!groupId) return; if (type === "audio") { let audioGroups = this._audioGroups; if (!audioGroups) audioGroups = this._audioGroups = []; if (audioGroups.indexOf(groupId) === -1) audioGroups.push(groupId); } else if (type === "text") { let subtitleGroups = this._subtitleGroups; if (!subtitleGroups) subtitleGroups = this._subtitleGroups = []; if (subtitleGroups.indexOf(groupId) === -1) subtitleGroups.push(groupId); } } get urlId() { return 0; } set urlId(value) {} get audioGroupIds() { return this.audioGroups ? [this.audioGroupId] : void 0; } get textGroupIds() { return this.subtitleGroups ? [this.textGroupId] : void 0; } get audioGroupId() { var _this$audioGroups; return (_this$audioGroups = this.audioGroups) == null ? void 0 : _this$audioGroups[0]; } get textGroupId() { var _this$subtitleGroups; return (_this$subtitleGroups = this.subtitleGroups) == null ? void 0 : _this$subtitleGroups[0]; } addFallback() {} }; function hasGroup(groups, groupId) { if (!groupId || !groups) return false; return groups.indexOf(groupId) !== -1; } /** * @returns Whether we can detect and validate HDR capability within the window context */ function isHdrSupported() { if (typeof matchMedia === "function") { const mediaQueryList = matchMedia("(dynamic-range: high)"); const badQuery = matchMedia("bad query"); if (mediaQueryList.media !== badQuery.media) return mediaQueryList.matches === true; } return false; } /** * Sanitizes inputs to return the active video selection options for HDR/SDR. * When both inputs are null: * * `{ preferHDR: false, allowedVideoRanges: [] }` * * When `currentVideoRange` non-null, maintain the active range: * * `{ preferHDR: currentVideoRange !== 'SDR', allowedVideoRanges: [currentVideoRange] }` * * When VideoSelectionOption non-null: * * - Allow all video ranges if `allowedVideoRanges` unspecified. * - If `preferHDR` is non-null use the value to filter `allowedVideoRanges`. * - Else check window for HDR support and set `preferHDR` to the result. * * @param currentVideoRange * @param videoPreference */ function getVideoSelectionOptions(currentVideoRange, videoPreference) { let preferHDR = false; let allowedVideoRanges = []; if (currentVideoRange) { preferHDR = currentVideoRange !== "SDR"; allowedVideoRanges = [currentVideoRange]; } if (videoPreference) { allowedVideoRanges = videoPreference.allowedVideoRanges || VideoRangeValues.slice(0); const allowAutoPreferHDR = allowedVideoRanges.join("") !== "SDR" && !videoPreference.videoCodec; preferHDR = videoPreference.preferHDR !== void 0 ? videoPreference.preferHDR : allowAutoPreferHDR && isHdrSupported(); if (!preferHDR) allowedVideoRanges = ["SDR"]; } return { preferHDR, allowedVideoRanges }; } var omitCircularRefsReplacer = (replacer) => { const known = /* @__PURE__ */ new WeakSet(); return (_, value) => { if (replacer) value = replacer(_, value); if (typeof value === "object" && value !== null) { if (known.has(value)) return; known.add(value); } return value; }; }; var stringify = (object, replacer) => JSON.stringify(object, omitCircularRefsReplacer(replacer)); function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPreference, videoPreference) { const codecSets = Object.keys(codecTiers); const channelsPreference = audioPreference == null ? void 0 : audioPreference.channels; const audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec; const videoCodecPreference = videoPreference == null ? void 0 : videoPreference.videoCodec; const preferStereo = channelsPreference && parseInt(channelsPreference) === 2; let hasStereo = false; let hasCurrentVideoRange = false; let minHeight = Infinity; let minFramerate = Infinity; let minBitrate = Infinity; let minIndex = Infinity; let selectedScore = 0; let videoRanges = []; const { preferHDR, allowedVideoRanges } = getVideoSelectionOptions(currentVideoRange, videoPreference); for (let i = codecSets.length; i--;) { const tier = codecTiers[codecSets[i]]; hasStereo || (hasStereo = tier.channels[2] > 0); minHeight = Math.min(minHeight, tier.minHeight); minFramerate = Math.min(minFramerate, tier.minFramerate); minBitrate = Math.min(minBitrate, tier.minBitrate); if (allowedVideoRanges.filter((range) => tier.videoRanges[range] > 0).length > 0) hasCurrentVideoRange = true; } minHeight = isFiniteNumber(minHeight) ? minHeight : 0; minFramerate = isFiniteNumber(minFramerate) ? minFramerate : 0; const maxHeight = Math.max(1080, minHeight); const maxFramerate = Math.max(30, minFramerate); minBitrate = isFiniteNumber(minBitrate) ? minBitrate : currentBw; currentBw = Math.max(minBitrate, currentBw); if (!hasCurrentVideoRange) currentVideoRange = void 0; const hasMultipleSets = codecSets.length > 1; return { codecSet: codecSets.reduce((selected, candidate) => { const candidateTier = codecTiers[candidate]; if (candidate === selected) return selected; videoRanges = hasCurrentVideoRange ? allowedVideoRanges.filter((range) => candidateTier.videoRanges[range] > 0) : []; if (hasMultipleSets) { if (candidateTier.minBitrate > currentBw) { logStartCodecCandidateIgnored(candidate, `min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`); return selected; } if (!candidateTier.hasDefaultAudio) { logStartCodecCandidateIgnored(candidate, `no renditions with default or auto-select sound found`); return selected; } if (audioCodecPreference && candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0) { logStartCodecCandidateIgnored(candidate, `audio codec preference "${audioCodecPreference}" not found`); return selected; } if (channelsPreference && !preferStereo) { if (!candidateTier.channels[channelsPreference]) { logStartCodecCandidateIgnored(candidate, `no renditions with ${channelsPreference} channel sound found (channels options: ${Object.keys(candidateTier.channels)})`); return selected; } } else if ((!audioCodecPreference || preferStereo) && hasStereo && candidateTier.channels["2"] === 0) { logStartCodecCandidateIgnored(candidate, `no renditions with stereo sound found`); return selected; } if (candidateTier.minHeight > maxHeight) { logStartCodecCandidateIgnored(candidate, `min resolution of ${candidateTier.minHeight} > maximum of ${maxHeight}`); return selected; } if (candidateTier.minFramerate > maxFramerate) { logStartCodecCandidateIgnored(candidate, `min framerate of ${candidateTier.minFramerate} > maximum of ${maxFramerate}`); return selected; } if (!videoRanges.some((range) => candidateTier.videoRanges[range] > 0)) { logStartCodecCandidateIgnored(candidate, `no variants with VIDEO-RANGE of ${stringify(videoRanges)} found`); return selected; } if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) { logStartCodecCandidateIgnored(candidate, `video codec preference "${videoCodecPreference}" not found`); return selected; } if (candidateTier.maxScore < selectedScore) { logStartCodecCandidateIgnored(candidate, `max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`); return selected; } } if (selected && (codecsSetSelectionPreferenceValue(candidate) >= codecsSetSelectionPreferenceValue(selected) || candidateTier.fragmentError > codecTiers[selected].fragmentError)) return selected; minIndex = candidateTier.minIndex; selectedScore = candidateTier.maxScore; return candidate; }, void 0), videoRanges, preferHDR, minFramerate, minBitrate, minIndex }; } function logStartCodecCandidateIgnored(codeSet, reason) { logger.log(`[abr] start candidates with "${codeSet}" ignored because ${reason}`); } function getAudioTracksByGroup(allAudioTracks) { return allAudioTracks.reduce((audioTracksByGroup, track) => { let trackGroup = audioTracksByGroup.groups[track.groupId]; if (!trackGroup) trackGroup = audioTracksByGroup.groups[track.groupId] = { tracks: [], channels: { 2: 0 }, hasDefault: false, hasAutoSelect: false }; trackGroup.tracks.push(track); const channelsKey = track.channels || "2"; trackGroup.channels[channelsKey] = (trackGroup.channels[channelsKey] || 0) + 1; trackGroup.hasDefault = trackGroup.hasDefault || track.default; trackGroup.hasAutoSelect = trackGroup.hasAutoSelect || track.autoselect; if (trackGroup.hasDefault) audioTracksByGroup.hasDefaultAudio = true; if (trackGroup.hasAutoSelect) audioTracksByGroup.hasAutoSelectAudio = true; return audioTracksByGroup; }, { hasDefaultAudio: false, hasAutoSelectAudio: false, groups: {} }); } function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) { return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce((tiers, level, index) => { if (!level.codecSet) return tiers; const audioGroups = level.audioGroups; let tier = tiers[level.codecSet]; if (!tier) tiers[level.codecSet] = tier = { minBitrate: Infinity, minHeight: Infinity, minFramerate: Infinity, minIndex: index, maxScore: 0, videoRanges: { SDR: 0 }, channels: { "2": 0 }, hasDefaultAudio: !audioGroups, fragmentError: 0 }; tier.minBitrate = Math.min(tier.minBitrate, level.bitrate); const lesserWidthOrHeight = Math.min(level.height, level.width); tier.minHeight = Math.min(tier.minHeight, lesserWidthOrHeight); tier.minFramerate = Math.min(tier.minFramerate, level.frameRate); tier.minIndex = Math.min(tier.minIndex, index); tier.maxScore = Math.max(tier.maxScore, level.score); tier.fragmentError += level.fragmentError; tier.videoRanges[level.videoRange] = (tier.videoRanges[level.videoRange] || 0) + 1; if (audioGroups) audioGroups.forEach((audioGroupId) => { if (!audioGroupId) return; const audioGroup = audioTracksByGroup.groups[audioGroupId]; if (!audioGroup) return; tier.hasDefaultAudio = tier.hasDefaultAudio || audioTracksByGroup.hasDefaultAudio ? audioGroup.hasDefault : audioGroup.hasAutoSelect || !audioTracksByGroup.hasDefaultAudio && !audioTracksByGroup.hasAutoSelectAudio; Object.keys(audioGroup.channels).forEach((channels) => { tier.channels[channels] = (tier.channels[channels] || 0) + audioGroup.channels[channels]; }); }); return tiers; }, {}); } function getBasicSelectionOption(option) { if (!option) return option; const { lang, assocLang, characteristics, channels, audioCodec } = option; return { lang, assocLang, characteristics, channels, audioCodec }; } function findMatchingOption(option, tracks, matchPredicate) { if ("attrs" in option) { const index = tracks.indexOf(option); if (index !== -1) return index; } for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; if (matchesOption(option, track, matchPredicate)) return i; } return -1; } function matchesOption(option, track, matchPredicate) { const { groupId, name, lang, assocLang, default: isDefault } = option; const forced = option.forced; return (groupId === void 0 || track.groupId === groupId) && (name === void 0 || track.name === name) && (lang === void 0 || languagesMatch(lang, track.lang)) && (lang === void 0 || track.assocLang === assocLang) && (isDefault === void 0 || track.default === isDefault) && (forced === void 0 || track.forced === forced) && (!("characteristics" in option) || characteristicsMatch(option.characteristics || "", track.characteristics)) && (matchPredicate === void 0 || matchPredicate(option, track)); } function languagesMatch(languageA, languageB = "--") { if (languageA.length === languageB.length) return languageA === languageB; return languageA.startsWith(languageB) || languageB.startsWith(languageA); } function characteristicsMatch(characteristicsA, characteristicsB = "") { const arrA = characteristicsA.split(","); const arrB = characteristicsB.split(","); return arrA.length === arrB.length && !arrA.some((el) => arrB.indexOf(el) === -1); } function audioMatchPredicate(option, track) { const { audioCodec, channels } = option; return (audioCodec === void 0 || (track.audioCodec || "").substring(0, 4) === audioCodec.substring(0, 4)) && (channels === void 0 || channels === (track.channels || "2")); } function findClosestLevelWithAudioGroup(option, levels, allAudioTracks, searchIndex, matchPredicate) { const currentLevel = levels[searchIndex]; const renditions = levels.reduce((variantMap, level, index) => { const uri = level.uri; (variantMap[uri] || (variantMap[uri] = [])).push(index); return variantMap; }, {})[currentLevel.uri]; if (renditions.length > 1) searchIndex = Math.max.apply(Math, renditions); const currentVideoRange = currentLevel.videoRange; const currentFrameRate = currentLevel.frameRate; const currentVideoCodec = currentLevel.codecSet.substring(0, 4); const matchingVideo = searchDownAndUpList(levels, searchIndex, (level) => { if (level.videoRange !== currentVideoRange || level.frameRate !== currentFrameRate || level.codecSet.substring(0, 4) !== currentVideoCodec) return false; const audioGroups = level.audioGroups; return findMatchingOption(option, allAudioTracks.filter((track) => !audioGroups || audioGroups.indexOf(track.groupId) !== -1), matchPredicate) > -1; }); if (matchingVideo > -1) return matchingVideo; return searchDownAndUpList(levels, searchIndex, (level) => { const audioGroups = level.audioGroups; return findMatchingOption(option, allAudioTracks.filter((track) => !audioGroups || audioGroups.indexOf(track.groupId) !== -1), matchPredicate) > -1; }); } function searchDownAndUpList(arr, searchIndex, predicate) { for (let i = searchIndex; i > -1; i--) if (predicate(arr[i])) return i; for (let i = searchIndex + 1; i < arr.length; i++) if (predicate(arr[i])) return i; return -1; } function useAlternateAudio(audioTrackUrl, hls) { var _hls$loadLevelObj; return !!audioTrackUrl && audioTrackUrl !== ((_hls$loadLevelObj = hls.loadLevelObj) == null ? void 0 : _hls$loadLevelObj.uri); } var AbrController = class extends Logger { constructor(_hls) { super("abr", _hls.logger); this.hls = void 0; this.lastLevelLoadSec = 0; this.lastLoadedFragLevel = -1; this.firstSelection = -1; this._nextAutoLevel = -1; this.nextAutoLevelKey = ""; this.audioTracksByGroup = null; this.codecTiers = null; this.timer = -1; this.fragCurrent = null; this.partCurrent = null; this.bitrateTestDelay = 0; this.rebufferNotice = -1; this.supportedCache = {}; this.bwEstimator = void 0; this._abandonRulesCheck = (levelLoaded) => { var _ref; const { fragCurrent: frag, partCurrent: part, hls } = this; const { autoLevelEnabled, media } = hls; if (!frag || !media) return; const now = performance.now(); const stats = part ? part.stats : frag.stats; const duration = part ? part.duration : frag.duration; const timeLoading = now - stats.loading.start; const minAutoLevel = hls.minAutoLevel; const loadingFragForLevel = frag.level; const currentAutoLevel = this._nextAutoLevel; if (stats.aborted || stats.loaded && stats.loaded === stats.total || loadingFragForLevel <= minAutoLevel) { this.clearTimer(); this._nextAutoLevel = -1; return; } if (!autoLevelEnabled) return; const fragBlockingSwitch = currentAutoLevel > -1 && currentAutoLevel !== loadingFragForLevel; const levelChange = !!levelLoaded || fragBlockingSwitch; if (!levelChange && (media.paused || !media.playbackRate || !media.readyState)) return; const bufferInfo = hls.mainForwardBufferInfo; if (!levelChange && bufferInfo === null) return; const ttfbEstimate = this.bwEstimator.getEstimateTTFB(); const playbackRate = Math.abs(media.playbackRate); if (timeLoading <= Math.max(ttfbEstimate, 1e3 * (duration / (playbackRate * 2)))) return; const bufferStarvationDelay = bufferInfo ? bufferInfo.len / playbackRate : 0; const ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1; const loadedFirstByte = stats.loaded && ttfb > -1; const bwEstimate = this.getBwEstimate(); const levels = hls.levels; const level = levels[loadingFragForLevel]; const expectedLen = Math.max(stats.loaded, Math.round(duration * (frag.bitrate || level.averageBitrate) / 8)); let timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading; if (timeStreaming < 1 && loadedFirstByte) timeStreaming = Math.min(timeLoading, stats.loaded * 8 / bwEstimate); const loadRate = loadedFirstByte ? stats.loaded * 1e3 / timeStreaming : 0; const ttfbSeconds = ttfbEstimate / 1e3; const fragLoadedDelay = loadRate ? (expectedLen - stats.loaded) / loadRate : expectedLen * 8 / bwEstimate + ttfbSeconds; if (fragLoadedDelay <= bufferStarvationDelay) return; const bwe = loadRate ? loadRate * 8 : bwEstimate; const live = ((_ref = (levelLoaded == null ? void 0 : levelLoaded.details) || this.hls.latestLevelDetails) == null ? void 0 : _ref.live) === true; const abrBandWidthUpFactor = this.hls.config.abrBandWidthUpFactor; let fragLevelNextLoadedDelay = Number.POSITIVE_INFINITY; let nextLoadLevel; for (nextLoadLevel = loadingFragForLevel - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) { const levelNextBitrate = levels[nextLoadLevel].maxBitrate; const requiresLevelLoad = !levels[nextLoadLevel].details || live; fragLevelNextLoadedDelay = this.getTimeToLoadFrag(ttfbSeconds, bwe, duration * levelNextBitrate, requiresLevelLoad); if (fragLevelNextLoadedDelay < Math.min(bufferStarvationDelay, duration + ttfbSeconds)) break; } if (fragLevelNextLoadedDelay >= fragLoadedDelay) return; if (fragLevelNextLoadedDelay > duration * 10) return; if (loadedFirstByte) this.bwEstimator.sample(timeLoading - Math.min(ttfbEstimate, ttfb), stats.loaded); else this.bwEstimator.sampleTTFB(timeLoading); const nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate; if (this.getBwEstimate() * abrBandWidthUpFactor > nextLoadLevelBitrate) this.resetEstimator(nextLoadLevelBitrate); const bestSwitchLevel = this.findBestLevel(nextLoadLevelBitrate, minAutoLevel, nextLoadLevel, 0, bufferStarvationDelay, 1, 1); if (bestSwitchLevel > -1) nextLoadLevel = bestSwitchLevel; this.warn(`Fragment ${frag.sn}${part ? " part " + part.index : ""} of level ${loadingFragForLevel} is loading too slowly; Fragment duration: ${frag.duration.toFixed(3)} Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s Estimated load time for down switch fragment: ${fragLevelNextLoadedDelay.toFixed(3)} s TTFB estimate: ${ttfb | 0} ms Current BW estimate: ${isFiniteNumber(bwEstimate) ? bwEstimate | 0 : "Unknown"} bps New BW estimate: ${this.getBwEstimate() | 0} bps Switching to level ${nextLoadLevel} @ ${nextLoadLevelBitrate | 0} bps`); hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel; this.clearTimer(); const abortAndSwitch = () => { this.clearTimer(); if (this.fragCurrent === frag && this.hls.loadLevel === nextLoadLevel && nextLoadLevel > 0) { const bufferStarvationDelay = this.getStarvationDelay(); this.warn(`Aborting inflight request ${nextLoadLevel > 0 ? "and switching down" : ""} Fragment duration: ${frag.duration.toFixed(3)} s Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s`); frag.abortRequests(); this.fragCurrent = this.partCurrent = null; if (nextLoadLevel > minAutoLevel) { let lowestSwitchLevel = this.findBestLevel(this.hls.levels[minAutoLevel].bitrate, minAutoLevel, nextLoadLevel, 0, bufferStarvationDelay, 1, 1); if (lowestSwitchLevel === -1) lowestSwitchLevel = minAutoLevel; this.hls.nextLoadLevel = this.hls.nextAutoLevel = lowestSwitchLevel; this.resetEstimator(this.hls.levels[lowestSwitchLevel].bitrate); } } }; if (fragBlockingSwitch || fragLoadedDelay > fragLevelNextLoadedDelay * 2) abortAndSwitch(); else this.timer = self.setInterval(abortAndSwitch, fragLevelNextLoadedDelay * 1e3); hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, { frag, part, stats }); }; this.hls = _hls; this.bwEstimator = this.initEstimator(); this.registerListeners(); } resetEstimator(abrEwmaDefaultEstimate) { if (abrEwmaDefaultEstimate) { this.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`); this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate; } this.firstSelection = -1; this.bwEstimator = this.initEstimator(); } initEstimator() { const config = this.hls.config; return new EwmaBandWidthEstimator(config.abrEwmaSlowVoD, config.abrEwmaFastVoD, config.abrEwmaDefaultEstimate); } registerListeners() { const { hls } = this; hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.FRAG_LOADING, this.onFragLoading, this); hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this); hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); hls.on(Events.MAX_AUTO_LEVEL_UPDATED, this.onMaxAutoLevelUpdated, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const { hls } = this; if (!hls) return; hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.FRAG_LOADING, this.onFragLoading, this); hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this); hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); hls.off(Events.MAX_AUTO_LEVEL_UPDATED, this.onMaxAutoLevelUpdated, this); hls.off(Events.ERROR, this.onError, this); } destroy() { this.unregisterListeners(); this.clearTimer(); this.hls = this._abandonRulesCheck = this.supportedCache = null; this.fragCurrent = this.partCurrent = null; } onManifestLoading(event, data) { this.lastLoadedFragLevel = -1; this.firstSelection = -1; this.lastLevelLoadSec = 0; this.supportedCache = {}; this.fragCurrent = this.partCurrent = null; this.onLevelsUpdated(); this.clearTimer(); } onLevelsUpdated() { if (this.lastLoadedFragLevel > -1 && this.fragCurrent) this.lastLoadedFragLevel = this.fragCurrent.level; this._nextAutoLevel = -1; this.onMaxAutoLevelUpdated(); this.codecTiers = null; this.audioTracksByGroup = null; } onMaxAutoLevelUpdated() { this.firstSelection = -1; this.nextAutoLevelKey = ""; } onFragLoading(event, data) { const frag = data.frag; if (this.ignoreFragment(frag)) return; if (!frag.bitrateTest) { var _data$part; this.fragCurrent = frag; this.partCurrent = (_data$part = data.part) != null ? _data$part : null; } this.clearTimer(); this.timer = self.setInterval(this._abandonRulesCheck, 100); } onLevelSwitching(event, data) { this.clearTimer(); } onError(event, data) { if (data.fatal) return; switch (data.details) { case ErrorDetails.BUFFER_ADD_CODEC_ERROR: case ErrorDetails.BUFFER_APPEND_ERROR: this.lastLoadedFragLevel = -1; this.firstSelection = -1; break; case ErrorDetails.FRAG_LOAD_TIMEOUT: { const frag = data.frag; const { fragCurrent, partCurrent: part } = this; if (frag && fragCurrent && frag.sn === fragCurrent.sn && frag.level === fragCurrent.level) { const now = performance.now(); const stats = part ? part.stats : frag.stats; const timeLoading = now - stats.loading.start; const ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1; if (stats.loaded && ttfb > -1) { const ttfbEstimate = this.bwEstimator.getEstimateTTFB(); this.bwEstimator.sample(timeLoading - Math.min(ttfbEstimate, ttfb), stats.loaded); } else this.bwEstimator.sampleTTFB(timeLoading); } break; } } } getTimeToLoadFrag(timeToFirstByteSec, bandwidth, fragSizeBits, isSwitch) { return timeToFirstByteSec + fragSizeBits / bandwidth + (isSwitch ? timeToFirstByteSec + this.lastLevelLoadSec : 0); } onLevelLoaded(event, data) { const config = this.hls.config; const { loading } = data.stats; const timeLoadingMs = loading.end - loading.first; if (isFiniteNumber(timeLoadingMs)) this.lastLevelLoadSec = timeLoadingMs / 1e3; if (data.details.live) this.bwEstimator.update(config.abrEwmaSlowLive, config.abrEwmaFastLive); else this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD); if (this.timer > -1) this._abandonRulesCheck(data.levelInfo); } onFragLoaded(event, { frag, part }) { const stats = part ? part.stats : frag.stats; if (frag.type === PlaylistLevelType.MAIN) this.bwEstimator.sampleTTFB(stats.loading.first - stats.loading.start); if (this.ignoreFragment(frag)) return; this.clearTimer(); if (frag.level === this._nextAutoLevel) this._nextAutoLevel = -1; this.firstSelection = -1; if (this.hls.config.abrMaxWithRealBitrate) { const duration = part ? part.duration : frag.duration; const level = this.hls.levels[frag.level]; const loadedBytes = (level.loaded ? level.loaded.bytes : 0) + stats.loaded; const loadedDuration = (level.loaded ? level.loaded.duration : 0) + duration; level.loaded = { bytes: loadedBytes, duration: loadedDuration }; level.realBitrate = Math.round(8 * loadedBytes / loadedDuration); } if (frag.bitrateTest) { const fragBufferedData = { stats, frag, part, id: frag.type }; this.onFragBuffered(Events.FRAG_BUFFERED, fragBufferedData); frag.bitrateTest = false; } else this.lastLoadedFragLevel = frag.level; } onFragBuffered(event, data) { const { frag, part } = data; const stats = part != null && part.stats.loaded ? part.stats : frag.stats; if (stats.aborted) return; if (this.ignoreFragment(frag)) return; const processingMs = stats.parsing.end - stats.loading.start - Math.min(stats.loading.first - stats.loading.start, this.bwEstimator.getEstimateTTFB()); this.bwEstimator.sample(processingMs, stats.loaded); stats.bwEstimate = this.getBwEstimate(); if (frag.bitrateTest) this.bitrateTestDelay = processingMs / 1e3; else this.bitrateTestDelay = 0; } ignoreFragment(frag) { return frag.type !== PlaylistLevelType.MAIN || frag.sn === "initSegment"; } clearTimer() { if (this.timer > -1) { self.clearInterval(this.timer); this.timer = -1; } } get firstAutoLevel() { const { maxAutoLevel, minAutoLevel } = this.hls; const bwEstimate = this.getBwEstimate(); const maxStartDelay = this.hls.config.maxStarvationDelay; const abrAutoLevel = this.findBestLevel(bwEstimate, minAutoLevel, maxAutoLevel, 0, maxStartDelay, 1, 1); if (abrAutoLevel > -1) return abrAutoLevel; const firstLevel = this.hls.firstLevel; const clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel); this.warn(`Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`); return clamped; } get forcedAutoLevel() { if (this.nextAutoLevelKey) return -1; return this._nextAutoLevel; } get nextAutoLevel() { const forcedAutoLevel = this.forcedAutoLevel; const useEstimate = this.bwEstimator.canEstimate(); const loadedFirstFrag = this.lastLoadedFragLevel > -1; if (forcedAutoLevel !== -1 && (!useEstimate || !loadedFirstFrag || this.nextAutoLevelKey === this.getAutoLevelKey())) return forcedAutoLevel; const nextABRAutoLevel = useEstimate && loadedFirstFrag ? this.getNextABRAutoLevel() : this.firstAutoLevel; if (forcedAutoLevel !== -1) { const levels = this.hls.levels; if (levels.length > Math.max(forcedAutoLevel, nextABRAutoLevel) && levels[forcedAutoLevel].loadError <= levels[nextABRAutoLevel].loadError) return forcedAutoLevel; } this._nextAutoLevel = nextABRAutoLevel; this.nextAutoLevelKey = this.getAutoLevelKey(); return nextABRAutoLevel; } getAutoLevelKey() { return `${this.getBwEstimate()}_${this.getStarvationDelay().toFixed(2)}`; } getNextABRAutoLevel() { const { fragCurrent, partCurrent, hls } = this; if (hls.levels.length <= 1) return hls.loadLevel; const { maxAutoLevel, config, minAutoLevel } = hls; const currentFragDuration = partCurrent ? partCurrent.duration : fragCurrent ? fragCurrent.duration : 0; const avgbw = this.getBwEstimate(); const bufferStarvationDelay = this.getStarvationDelay(); let bwFactor = config.abrBandWidthFactor; let bwUpFactor = config.abrBandWidthUpFactor; if (bufferStarvationDelay) { const _bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, 0, bwFactor, bwUpFactor); if (_bestLevel >= 0) { this.rebufferNotice = -1; return _bestLevel; } } let maxStarvationDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxStarvationDelay) : config.maxStarvationDelay; if (!bufferStarvationDelay) { const bitrateTestDelay = this.bitrateTestDelay; if (bitrateTestDelay) { maxStarvationDelay = (currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay) - bitrateTestDelay; this.info(`bitrate test took ${Math.round(1e3 * bitrateTestDelay)}ms, set first fragment max fetchDuration to ${Math.round(1e3 * maxStarvationDelay)} ms`); bwFactor = bwUpFactor = 1; } } const bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor); if (this.rebufferNotice !== bestLevel) { this.rebufferNotice = bestLevel; this.info(`${bufferStarvationDelay ? "rebuffering expected" : "buffer is empty"}, optimal quality level ${bestLevel}`); } if (bestLevel > -1) return bestLevel; const minLevel = hls.levels[minAutoLevel]; const autoLevel = hls.loadLevelObj; if (autoLevel && (minLevel == null ? void 0 : minLevel.bitrate) < autoLevel.bitrate) return minAutoLevel; return hls.loadLevel; } getStarvationDelay() { const hls = this.hls; const media = hls.media; if (!media) return Infinity; const playbackRate = media && media.playbackRate !== 0 ? Math.abs(media.playbackRate) : 1; const bufferInfo = hls.mainForwardBufferInfo; return (bufferInfo ? bufferInfo.len : 0) / playbackRate; } getBwEstimate() { return this.bwEstimator.canEstimate() ? this.bwEstimator.getEstimate() : this.hls.config.abrEwmaDefaultEstimate; } findBestLevel(currentBw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor) { var _this$hls$latestLevel; const maxFetchDuration = bufferStarvationDelay + maxStarvationDelay; const lastLoadedFragLevel = this.lastLoadedFragLevel; const selectionBaseLevel = lastLoadedFragLevel === -1 ? this.hls.firstLevel : lastLoadedFragLevel; const { fragCurrent, partCurrent } = this; const { levels, allAudioTracks, loadLevel, config } = this.hls; if (levels.length === 1) return 0; const level = levels[selectionBaseLevel]; const live = !!((_this$hls$latestLevel = this.hls.latestLevelDetails) != null && _this$hls$latestLevel.live); const firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1; let currentCodecSet; let currentVideoRange = "SDR"; let currentFrameRate = (level == null ? void 0 : level.frameRate) || 0; const { audioPreference, videoPreference } = config; const audioTracksByGroup = this.audioTracksByGroup || (this.audioTracksByGroup = getAudioTracksByGroup(allAudioTracks)); let minStartIndex = -1; if (firstSelection) { if (this.firstSelection !== -1) return this.firstSelection; const startTier = getStartCodecTier(this.codecTiers || (this.codecTiers = getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel)), currentVideoRange, currentBw, audioPreference, videoPreference); const { codecSet, videoRanges, minFramerate, minBitrate, minIndex, preferHDR } = startTier; minStartIndex = minIndex; currentCodecSet = codecSet; currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0]; currentFrameRate = minFramerate; currentBw = Math.max(currentBw, minBitrate); this.log(`picked start tier ${stringify(startTier)}`); } else { currentCodecSet = level == null ? void 0 : level.codecSet; currentVideoRange = level == null ? void 0 : level.videoRange; } const currentFragDuration = partCurrent ? partCurrent.duration : fragCurrent ? fragCurrent.duration : 0; const ttfbEstimateSec = this.bwEstimator.getEstimateTTFB() / 1e3; const levelsSkipped = []; for (let i = maxAutoLevel; i >= minAutoLevel; i--) { var _levelInfo$supportedR; const levelInfo = levels[i]; const upSwitch = i > selectionBaseLevel; if (!levelInfo) continue; if (config.useMediaCapabilities && !levelInfo.supportedResult && !levelInfo.supportedPromise) { const mediaCapabilities = navigator.mediaCapabilities; if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === "function" && requiresMediaCapabilitiesDecodingInfo(levelInfo, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference)) { levelInfo.supportedPromise = getMediaDecodingInfoPromise(levelInfo, audioTracksByGroup, mediaCapabilities, this.supportedCache); levelInfo.supportedPromise.then((decodingInfo) => { if (!this.hls) return; levelInfo.supportedResult = decodingInfo; const levels = this.hls.levels; const index = levels.indexOf(levelInfo); if (decodingInfo.error) this.warn(`MediaCapabilities decodingInfo error: "${decodingInfo.error}" for level ${index} ${stringify(decodingInfo)}`); else if (!decodingInfo.supported) { this.warn(`Unsupported MediaCapabilities decodingInfo result for level ${index} ${stringify(decodingInfo)}`); if (index > -1 && levels.length > 1) { this.log(`Removing unsupported level ${index}`); this.hls.removeLevel(index); if (this.hls.loadLevel === -1) this.hls.nextLoadLevel = 0; } } else if (decodingInfo.decodingInfoResults.some((info) => info.smooth === false || info.powerEfficient === false)) this.log(`MediaCapabilities decodingInfo for level ${index} not smooth or powerEfficient: ${stringify(decodingInfo)}`); }).catch((error) => { this.warn(`Error handling MediaCapabilities decodingInfo: ${error}`); }); } else levelInfo.supportedResult = SUPPORTED_INFO_DEFAULT; } if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || (_levelInfo$supportedR = levelInfo.supportedResult) != null && (_levelInfo$supportedR = _levelInfo$supportedR.decodingInfoResults) != null && _levelInfo$supportedR.some((info) => info.smooth === false)) { if (!firstSelection || i !== minStartIndex) { levelsSkipped.push(i); continue; } } const levelDetails = levelInfo.details; const avgDuration = (partCurrent ? levelDetails == null ? void 0 : levelDetails.partTarget : levelDetails == null ? void 0 : levelDetails.averagetargetduration) || currentFragDuration; let adjustedbw; if (!upSwitch) adjustedbw = bwFactor * currentBw; else adjustedbw = bwUpFactor * currentBw; const bitrate = currentFragDuration && bufferStarvationDelay >= currentFragDuration * 2 && maxStarvationDelay === 0 ? levelInfo.averageBitrate : levelInfo.maxBitrate; const fetchDuration = this.getTimeToLoadFrag(ttfbEstimateSec, adjustedbw, bitrate * avgDuration, levelDetails === void 0); if (adjustedbw >= bitrate && (i === lastLoadedFragLevel || levelInfo.loadError === 0 && levelInfo.fragmentError === 0) && (fetchDuration <= ttfbEstimateSec || !isFiniteNumber(fetchDuration) || live && !this.bitrateTestDelay || fetchDuration < maxFetchDuration)) { const forcedAutoLevel = this.forcedAutoLevel; if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) { if (levelsSkipped.length) this.trace(`Skipped level(s) ${levelsSkipped.join(",")} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${levels[levelsSkipped[0]].codecs}" ${levels[levelsSkipped[0]].videoRange}; not compatible with "${currentCodecSet}" ${currentVideoRange}`); this.info(`switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(adjustedbw)})-bitrate=${Math.round(adjustedbw - bitrate)} ttfb:${ttfbEstimateSec.toFixed(1)} avgDuration:${avgDuration.toFixed(1)} maxFetchDuration:${maxFetchDuration.toFixed(1)} fetchDuration:${fetchDuration.toFixed(1)} firstSelection:${firstSelection} codecSet:${levelInfo.codecSet} videoRange:${levelInfo.videoRange} hls.loadLevel:${loadLevel}`); } if (firstSelection) this.firstSelection = i; return i; } } return -1; } set nextAutoLevel(nextLevel) { const value = this.deriveNextAutoLevel(nextLevel); if (this._nextAutoLevel !== value) { this.nextAutoLevelKey = ""; this._nextAutoLevel = value; } } deriveNextAutoLevel(nextLevel) { const { maxAutoLevel, minAutoLevel } = this.hls; return Math.min(Math.max(nextLevel, minAutoLevel), maxAutoLevel); } }; var BinarySearch = { /** * Searches for an item in an array which matches a certain condition. * This requires the condition to only match one item in the array, * and for the array to be ordered. * * @param list The array to search. * @param comparisonFn * Called and provided a candidate item as the first argument. * Should return: * > -1 if the item should be located at a lower index than the provided item. * > 1 if the item should be located at a higher index than the provided item. * > 0 if the item is the item you're looking for. * * @returns the object if found, otherwise returns null */ search: function(list, comparisonFn) { let minIndex = 0; let maxIndex = list.length - 1; let currentIndex = null; let currentElement = null; while (minIndex <= maxIndex) { currentIndex = (minIndex + maxIndex) / 2 | 0; currentElement = list[currentIndex]; const comparisonResult = comparisonFn(currentElement); if (comparisonResult > 0) minIndex = currentIndex + 1; else if (comparisonResult < 0) maxIndex = currentIndex - 1; else return currentElement; } return null; } }; /** * Returns first fragment whose endPdt value exceeds the given PDT, or null. * @param fragments - The array of candidate fragments * @param PDTValue - The PDT value which must be exceeded * @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous */ function findFragmentByPDT(fragments, PDTValue, maxFragLookUpTolerance) { if (PDTValue === null || !Array.isArray(fragments) || !fragments.length || !isFiniteNumber(PDTValue)) return null; if (PDTValue < (fragments[0].programDateTime || 0)) return null; if (PDTValue >= (fragments[fragments.length - 1].endProgramDateTime || 0)) return null; for (let seg = 0; seg < fragments.length; ++seg) { const frag = fragments[seg]; if (pdtWithinToleranceTest(PDTValue, maxFragLookUpTolerance, frag)) return frag; } return null; } /** * Finds a fragment based on the SN of the previous fragment; or based on the needs of the current buffer. * This method compensates for small buffer gaps by applying a tolerance to the start of any candidate fragment, thus * breaking any traps which would cause the same fragment to be continuously selected within a small range. * @param fragPrevious - The last frag successfully appended * @param fragments - The array of candidate fragments * @param bufferEnd - The end of the contiguous buffered range the playhead is currently within * @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous * @returns a matching fragment or null */ function findFragmentByPTS(fragPrevious, fragments, bufferEnd = 0, maxFragLookUpTolerance = 0, nextFragLookupTolerance = .005) { let fragNext = null; if (fragPrevious) { fragNext = fragments[1 + fragPrevious.sn - fragments[0].sn] || null; const bufferEdgeError = fragPrevious.endDTS - bufferEnd; if (bufferEdgeError > 0 && bufferEdgeError < 15e-7) bufferEnd += 15e-7; if (fragNext && fragPrevious.level !== fragNext.level && fragNext.end <= fragPrevious.end) fragNext = fragments[2 + fragPrevious.sn - fragments[0].sn] || null; } else if (bufferEnd === 0 && fragments[0].start === 0) fragNext = fragments[0]; if (fragNext && ((!fragPrevious || fragPrevious.level === fragNext.level) && fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, fragNext) === 0 || fragmentWithinFastStartSwitch(fragNext, fragPrevious, Math.min(nextFragLookupTolerance, maxFragLookUpTolerance)))) return fragNext; const foundFragment = BinarySearch.search(fragments, fragmentWithinToleranceTest.bind(null, bufferEnd, maxFragLookUpTolerance)); if (foundFragment && (foundFragment !== fragPrevious || !fragNext)) return foundFragment; return fragNext; } function fragmentWithinFastStartSwitch(fragNext, fragPrevious, nextFragLookupTolerance) { if (fragPrevious && fragPrevious.start === 0 && fragPrevious.level < fragNext.level && (fragPrevious.endPTS || 0) > 0) { const firstDuration = fragPrevious.tagList.reduce((duration, tag) => { if (tag[0] === "INF") duration += parseFloat(tag[1]); return duration; }, nextFragLookupTolerance); return fragNext.start <= firstDuration; } return false; } /** * The test function used by the findFragmentBySn's BinarySearch to look for the best match to the current buffer conditions. * @param candidate - The fragment to test * @param bufferEnd - The end of the current buffered range the playhead is currently within * @param maxFragLookUpTolerance - The amount of time that a fragment's start can be within in order to be considered contiguous * @returns 0 if it matches, 1 if too low, -1 if too high */ function fragmentWithinToleranceTest(bufferEnd = 0, maxFragLookUpTolerance = 0, candidate) { if (candidate.start <= bufferEnd && candidate.start + candidate.duration > bufferEnd) return 0; const candidateLookupTolerance = Math.min(maxFragLookUpTolerance, candidate.duration + (candidate.deltaPTS ? candidate.deltaPTS : 0)); if (candidate.start + candidate.duration - candidateLookupTolerance <= bufferEnd) return 1; else if (candidate.start - candidateLookupTolerance > bufferEnd && candidate.start) return -1; return 0; } /** * The test function used by the findFragmentByPdt's BinarySearch to look for the best match to the current buffer conditions. * This function tests the candidate's program date time values, as represented in Unix time * @param candidate - The fragment to test * @param pdtBufferEnd - The Unix time representing the end of the current buffered range * @param maxFragLookUpTolerance - The amount of time that a fragment's start can be within in order to be considered contiguous * @returns true if contiguous, false otherwise */ function pdtWithinToleranceTest(pdtBufferEnd, maxFragLookUpTolerance, candidate) { const candidateLookupTolerance = Math.min(maxFragLookUpTolerance, candidate.duration + (candidate.deltaPTS ? candidate.deltaPTS : 0)) * 1e3; return (candidate.endProgramDateTime || 0) - candidateLookupTolerance > pdtBufferEnd; } function findNearestWithCC(details, cc, pos) { if (details) { if (details.startCC <= cc && details.endCC >= cc) { let fragments = details.fragments; const { fragmentHint } = details; if (fragmentHint) fragments = fragments.concat(fragmentHint); let closest; BinarySearch.search(fragments, (candidate) => { if (candidate.cc < cc) return 1; if (candidate.cc > cc) return -1; closest = candidate; if (candidate.end <= pos) return 1; if (candidate.start > pos) return -1; return 0; }); return closest || null; } } return null; } function isTimeoutError(error) { switch (error.details) { case ErrorDetails.FRAG_LOAD_TIMEOUT: case ErrorDetails.KEY_LOAD_TIMEOUT: case ErrorDetails.LEVEL_LOAD_TIMEOUT: case ErrorDetails.MANIFEST_LOAD_TIMEOUT: return true; } return false; } function isKeyError(error) { return error.details.startsWith("key"); } function isUnusableKeyError(error) { return isKeyError(error) && !!error.frag && !error.frag.decryptdata; } function getRetryConfig(loadPolicy, error) { const isTimeout = isTimeoutError(error); return loadPolicy.default[`${isTimeout ? "timeout" : "error"}Retry`]; } function getRetryDelay(retryConfig, retryCount) { const backoffFactor = retryConfig.backoff === "linear" ? 1 : Math.pow(2, retryCount); return Math.min(backoffFactor * retryConfig.retryDelayMs, retryConfig.maxRetryDelayMs); } function getLoaderConfigWithoutReties(loderConfig) { return _objectSpread2(_objectSpread2({}, loderConfig), { errorRetry: null, timeoutRetry: null }); } function shouldRetry(retryConfig, retryCount, isTimeout, loaderResponse) { if (!retryConfig) return false; const httpStatus = loaderResponse == null ? void 0 : loaderResponse.code; const retry = retryCount < retryConfig.maxNumRetry && (retryForHttpStatus(httpStatus) || !!isTimeout); return retryConfig.shouldRetry ? retryConfig.shouldRetry(retryConfig, retryCount, isTimeout, loaderResponse, retry) : retry; } function retryForHttpStatus(httpStatus) { return offlineHttpStatus(httpStatus) || !!httpStatus && (httpStatus < 400 || httpStatus > 499); } function offlineHttpStatus(httpStatus) { return httpStatus === 0 && navigator.onLine === false; } var NetworkErrorAction = { DoNothing: 0, SendEndCallback: 1, SendAlternateToPenaltyBox: 2, RemoveAlternatePermanently: 3, InsertDiscontinuity: 4, RetryRequest: 5 }; var ErrorActionFlags = { None: 0, MoveAllAlternatesMatchingHost: 1, MoveAllAlternatesMatchingHDCP: 2, MoveAllAlternatesMatchingKey: 4, SwitchToSDR: 8 }; var ErrorController = class extends Logger { constructor(hls) { super("error-controller", hls.logger); this.hls = void 0; this.playlistError = 0; this.hls = hls; this.registerListeners(); } registerListeners() { const hls = this.hls; hls.on(Events.ERROR, this.onError, this); hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this); } unregisterListeners() { const hls = this.hls; if (!hls) return; hls.off(Events.ERROR, this.onError, this); hls.off(Events.ERROR, this.onErrorOut, this); hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this); } destroy() { this.unregisterListeners(); this.hls = null; } startLoad(startPosition) {} stopLoad() { this.playlistError = 0; } getVariantLevelIndex(frag) { if ((frag == null ? void 0 : frag.type) === PlaylistLevelType.MAIN) return frag.level; return this.getVariantIndex(); } getVariantIndex() { var _hls$loadLevelObj; const hls = this.hls; const currentLevel = hls.currentLevel; if ((_hls$loadLevelObj = hls.loadLevelObj) != null && _hls$loadLevelObj.details || currentLevel === -1) return hls.loadLevel; return currentLevel; } variantHasKey(level, keyInError) { if (level) { var _level$details; if ((_level$details = level.details) != null && _level$details.hasKey(keyInError)) return true; const audioGroupsIds = level.audioGroups; if (audioGroupsIds) return this.hls.allAudioTracks.filter((track) => audioGroupsIds.indexOf(track.groupId) >= 0).some((track) => { var _track$details; return (_track$details = track.details) == null ? void 0 : _track$details.hasKey(keyInError); }); } return false; } onManifestLoading() { this.playlistError = 0; } onLevelUpdated() { this.playlistError = 0; } onError(event, data) { var _data$frag; if (data.fatal) return; const hls = this.hls; const context = data.context; switch (data.details) { case ErrorDetails.FRAG_LOAD_ERROR: case ErrorDetails.FRAG_LOAD_TIMEOUT: case ErrorDetails.KEY_LOAD_ERROR: case ErrorDetails.KEY_LOAD_TIMEOUT: data.errorAction = this.getFragRetryOrSwitchAction(data); return; case ErrorDetails.FRAG_PARSING_ERROR: if ((_data$frag = data.frag) != null && _data$frag.gap) { data.errorAction = createDoNothingErrorAction(); return; } case ErrorDetails.FRAG_GAP: case ErrorDetails.FRAG_DECRYPT_ERROR: data.errorAction = this.getFragRetryOrSwitchAction(data); data.errorAction.action = NetworkErrorAction.SendAlternateToPenaltyBox; return; case ErrorDetails.LEVEL_EMPTY_ERROR: case ErrorDetails.LEVEL_PARSING_ERROR: { var _data$context; const levelIndex = data.parent === PlaylistLevelType.MAIN ? data.level : hls.loadLevel; if (data.details === ErrorDetails.LEVEL_EMPTY_ERROR && !!((_data$context = data.context) != null && (_data$context = _data$context.levelDetails) != null && _data$context.live)) data.errorAction = this.getPlaylistRetryOrSwitchAction(data, levelIndex); else { data.levelRetry = false; data.errorAction = this.getLevelSwitchAction(data, levelIndex); } } return; case ErrorDetails.LEVEL_LOAD_ERROR: case ErrorDetails.LEVEL_LOAD_TIMEOUT: if (typeof (context == null ? void 0 : context.level) === "number") data.errorAction = this.getPlaylistRetryOrSwitchAction(data, context.level); return; case ErrorDetails.AUDIO_TRACK_LOAD_ERROR: case ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT: case ErrorDetails.SUBTITLE_LOAD_ERROR: case ErrorDetails.SUBTITLE_TRACK_LOAD_TIMEOUT: if (context) { const level = hls.loadLevelObj; if (level && (context.type === PlaylistContextType.AUDIO_TRACK && level.hasAudioGroup(context.groupId) || context.type === PlaylistContextType.SUBTITLE_TRACK && level.hasSubtitleGroup(context.groupId))) { data.errorAction = this.getPlaylistRetryOrSwitchAction(data, hls.loadLevel); data.errorAction.action = NetworkErrorAction.SendAlternateToPenaltyBox; data.errorAction.flags = ErrorActionFlags.MoveAllAlternatesMatchingHost; return; } } return; case ErrorDetails.KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED: data.errorAction = { action: NetworkErrorAction.SendAlternateToPenaltyBox, flags: ErrorActionFlags.MoveAllAlternatesMatchingHDCP }; return; case ErrorDetails.KEY_SYSTEM_SESSION_UPDATE_FAILED: case ErrorDetails.KEY_SYSTEM_STATUS_INTERNAL_ERROR: case ErrorDetails.KEY_SYSTEM_NO_SESSION: data.errorAction = { action: NetworkErrorAction.SendAlternateToPenaltyBox, flags: ErrorActionFlags.MoveAllAlternatesMatchingKey }; return; case ErrorDetails.BUFFER_ADD_CODEC_ERROR: case ErrorDetails.REMUX_ALLOC_ERROR: case ErrorDetails.BUFFER_APPEND_ERROR: if (!data.errorAction) { var _data$level; data.errorAction = this.getLevelSwitchAction(data, (_data$level = data.level) != null ? _data$level : hls.loadLevel); } return; case ErrorDetails.INTERNAL_EXCEPTION: case ErrorDetails.BUFFER_APPENDING_ERROR: case ErrorDetails.BUFFER_FULL_ERROR: case ErrorDetails.LEVEL_SWITCH_ERROR: case ErrorDetails.BUFFER_STALLED_ERROR: case ErrorDetails.BUFFER_SEEK_OVER_HOLE: case ErrorDetails.BUFFER_NUDGE_ON_STALL: data.errorAction = createDoNothingErrorAction(); return; } if (data.type === ErrorTypes.KEY_SYSTEM_ERROR) { data.levelRetry = false; data.errorAction = createDoNothingErrorAction(); } } getPlaylistRetryOrSwitchAction(data, levelIndex) { const hls = this.hls; const retryConfig = getRetryConfig(hls.config.playlistLoadPolicy, data); const retryCount = this.playlistError++; if (shouldRetry(retryConfig, retryCount, isTimeoutError(data), data.response)) return { action: NetworkErrorAction.RetryRequest, flags: ErrorActionFlags.None, retryConfig, retryCount }; const errorAction = this.getLevelSwitchAction(data, levelIndex); if (retryConfig) { errorAction.retryConfig = retryConfig; errorAction.retryCount = retryCount; } return errorAction; } getFragRetryOrSwitchAction(data) { const hls = this.hls; const variantLevelIndex = this.getVariantLevelIndex(data.frag); const level = hls.levels[variantLevelIndex]; const { fragLoadPolicy, keyLoadPolicy } = hls.config; const retryConfig = getRetryConfig(isKeyError(data) ? keyLoadPolicy : fragLoadPolicy, data); const fragmentErrors = hls.levels.reduce((acc, level) => acc + level.fragmentError, 0); if (level) { if (data.details !== ErrorDetails.FRAG_GAP) level.fragmentError++; if (!isUnusableKeyError(data)) { if (shouldRetry(retryConfig, fragmentErrors, isTimeoutError(data), data.response)) return { action: NetworkErrorAction.RetryRequest, flags: ErrorActionFlags.None, retryConfig, retryCount: fragmentErrors }; } } const errorAction = this.getLevelSwitchAction(data, variantLevelIndex); if (retryConfig) { errorAction.retryConfig = retryConfig; errorAction.retryCount = fragmentErrors; } return errorAction; } getLevelSwitchAction(data, levelIndex) { const hls = this.hls; if (levelIndex === null || levelIndex === void 0) levelIndex = hls.loadLevel; const level = this.hls.levels[levelIndex]; if (level) { var _data$frag2, _data$context2; const errorDetails = data.details; level.loadError++; if (errorDetails === ErrorDetails.BUFFER_APPEND_ERROR) level.fragmentError++; let nextLevel = -1; const { levels, loadLevel, minAutoLevel, maxAutoLevel } = hls; if (!hls.autoLevelEnabled && !hls.config.preserveManualLevelOnError) hls.loadLevel = -1; const fragErrorType = (_data$frag2 = data.frag) == null ? void 0 : _data$frag2.type; const findAudioCodecAlternate = (fragErrorType === PlaylistLevelType.AUDIO && errorDetails === ErrorDetails.FRAG_PARSING_ERROR || data.sourceBufferName === "audio" && (errorDetails === ErrorDetails.BUFFER_ADD_CODEC_ERROR || errorDetails === ErrorDetails.BUFFER_APPEND_ERROR)) && levels.some(({ audioCodec }) => level.audioCodec !== audioCodec); const findVideoCodecAlternate = data.sourceBufferName === "video" && (errorDetails === ErrorDetails.BUFFER_ADD_CODEC_ERROR || errorDetails === ErrorDetails.BUFFER_APPEND_ERROR) && levels.some(({ codecSet, audioCodec }) => level.codecSet !== codecSet && level.audioCodec === audioCodec); const { type: playlistErrorType, groupId: playlistErrorGroupId } = (_data$context2 = data.context) != null ? _data$context2 : {}; for (let i = levels.length; i--;) { const candidate = (i + loadLevel) % levels.length; if (candidate !== loadLevel && candidate >= minAutoLevel && candidate <= maxAutoLevel && levels[candidate].loadError === 0) { var _level$audioGroups, _level$subtitleGroups; const levelCandidate = levels[candidate]; if (errorDetails === ErrorDetails.FRAG_GAP && fragErrorType === PlaylistLevelType.MAIN && data.frag) { const levelDetails = levels[candidate].details; if (levelDetails) { const fragCandidate = findFragmentByPTS(data.frag, levelDetails.fragments, data.frag.start); if (fragCandidate != null && fragCandidate.gap) continue; } } else if (playlistErrorType === PlaylistContextType.AUDIO_TRACK && levelCandidate.hasAudioGroup(playlistErrorGroupId) || playlistErrorType === PlaylistContextType.SUBTITLE_TRACK && levelCandidate.hasSubtitleGroup(playlistErrorGroupId)) continue; else if (fragErrorType === PlaylistLevelType.AUDIO && (_level$audioGroups = level.audioGroups) != null && _level$audioGroups.some((groupId) => levelCandidate.hasAudioGroup(groupId)) || fragErrorType === PlaylistLevelType.SUBTITLE && (_level$subtitleGroups = level.subtitleGroups) != null && _level$subtitleGroups.some((groupId) => levelCandidate.hasSubtitleGroup(groupId)) || findAudioCodecAlternate && level.audioCodec === levelCandidate.audioCodec || findVideoCodecAlternate && level.codecSet === levelCandidate.codecSet || !findAudioCodecAlternate && level.codecSet !== levelCandidate.codecSet) continue; nextLevel = candidate; break; } } if (nextLevel > -1 && hls.loadLevel !== nextLevel) { data.levelRetry = true; this.playlistError = 0; return { action: NetworkErrorAction.SendAlternateToPenaltyBox, flags: ErrorActionFlags.None, nextAutoLevel: nextLevel }; } } return { action: NetworkErrorAction.SendAlternateToPenaltyBox, flags: ErrorActionFlags.MoveAllAlternatesMatchingHost }; } onErrorOut(event, data) { var _data$errorAction; switch ((_data$errorAction = data.errorAction) == null ? void 0 : _data$errorAction.action) { case NetworkErrorAction.DoNothing: break; case NetworkErrorAction.SendAlternateToPenaltyBox: this.sendAlternateToPenaltyBox(data); if (!data.errorAction.resolved && data.details !== ErrorDetails.FRAG_GAP) data.fatal = true; else if (/MediaSource readyState: ended/.test(data.error.message)) { this.warn(`MediaSource ended after "${data.sourceBufferName}" sourceBuffer append error. Attempting to recover from media error.`); this.hls.recoverMediaError(); } break; case NetworkErrorAction.RetryRequest: break; } if (data.fatal) { this.hls.stopLoad(); return; } } sendAlternateToPenaltyBox(data) { const hls = this.hls; const errorAction = data.errorAction; if (!errorAction) return; const { flags } = errorAction; const nextAutoLevel = errorAction.nextAutoLevel; switch (flags) { case ErrorActionFlags.None: this.switchLevel(data, nextAutoLevel); break; case ErrorActionFlags.MoveAllAlternatesMatchingHDCP: { const levelIndex = this.getVariantLevelIndex(data.frag); const level = hls.levels[levelIndex]; const restrictedHdcpLevel = level == null ? void 0 : level.attrs["HDCP-LEVEL"]; errorAction.hdcpLevel = restrictedHdcpLevel; if (restrictedHdcpLevel === "NONE") this.warn(`HDCP policy resticted output with HDCP-LEVEL=NONE`); else if (restrictedHdcpLevel) { hls.maxHdcpLevel = HdcpLevels[HdcpLevels.indexOf(restrictedHdcpLevel) - 1]; errorAction.resolved = true; this.warn(`Restricting playback to HDCP-LEVEL of "${hls.maxHdcpLevel}" or lower`); break; } } case ErrorActionFlags.MoveAllAlternatesMatchingKey: { const levelKey = data.decryptdata; if (levelKey) { const levels = this.hls.levels; const levelCountWithError = levels.length; for (let i = levelCountWithError; i--;) if (this.variantHasKey(levels[i], levelKey)) { var _levels$i$audioGroups, _data$frag3; this.log(`Banned key found in level ${i} (${levels[i].bitrate}bps) or audio group "${(_levels$i$audioGroups = levels[i].audioGroups) == null ? void 0 : _levels$i$audioGroups.join(",")}" (${(_data$frag3 = data.frag) == null ? void 0 : _data$frag3.type} fragment) ${arrayToHex(levelKey.keyId || [])}`); levels[i].fragmentError++; levels[i].loadError++; this.log(`Removing level ${i} with key error (${data.error})`); this.hls.removeLevel(i); } const frag = data.frag; if (this.hls.levels.length < levelCountWithError) errorAction.resolved = true; else if (frag && frag.type !== PlaylistLevelType.MAIN) { const fragLevelKey = frag.decryptdata; if (fragLevelKey && !levelKey.matches(fragLevelKey)) errorAction.resolved = true; } } break; } } if (!errorAction.resolved) this.switchLevel(data, nextAutoLevel); } switchLevel(data, levelIndex) { if (levelIndex !== void 0 && data.errorAction) { this.warn(`switching to level ${levelIndex} after ${data.details}`); this.hls.nextAutoLevel = levelIndex; data.errorAction.resolved = true; this.hls.nextLoadLevel = this.hls.nextAutoLevel; if (data.details === ErrorDetails.BUFFER_ADD_CODEC_ERROR && data.mimeType && data.sourceBufferName !== "audiovideo") { const codec = getCodecsForMimeType(data.mimeType); const levels = this.hls.levels; for (let i = levels.length; i--;) if (levels[i][`${data.sourceBufferName}Codec`] === codec) { this.log(`Removing level ${i} for ${data.details} ("${codec}" not supported)`); this.hls.removeLevel(i); } } } } }; function createDoNothingErrorAction(resolved) { const errorAction = { action: NetworkErrorAction.DoNothing, flags: ErrorActionFlags.None }; if (resolved) errorAction.resolved = true; return errorAction; } var FragmentState = { NOT_LOADED: "NOT_LOADED", APPENDING: "APPENDING", PARTIAL: "PARTIAL", OK: "OK" }; var FragmentTracker = class { constructor(hls) { this.activePartLists = Object.create(null); this.endListFragments = Object.create(null); this.fragments = Object.create(null); this.timeRanges = Object.create(null); this.bufferPadding = .2; this.hls = void 0; this.hasGaps = false; this.hls = hls; this._registerListeners(); } _registerListeners() { const { hls } = this; if (hls) { hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this); hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); } } _unregisterListeners() { const { hls } = this; if (hls) { hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this); hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); } } destroy() { this._unregisterListeners(); this.hls = this.fragments = this.activePartLists = this.endListFragments = this.timeRanges = null; } /** * Return a Fragment or Part with an appended range that matches the position and levelType * Otherwise, return null */ getAppendedFrag(position, levelType) { const activeParts = this.activePartLists[levelType]; if (activeParts) for (let i = activeParts.length; i--;) { const activePart = activeParts[i]; if (!activePart) break; if (activePart.start <= position && position <= activePart.end && activePart.loaded) return activePart; } return this.getBufferedFrag(position, levelType); } /** * Return a buffered Fragment that matches the position and levelType. * A buffered Fragment is one whose loading, parsing and appending is done (completed or "partial" meaning aborted). * If not found any Fragment, return null */ getBufferedFrag(position, levelType) { return this.getFragAtPos(position, levelType, true); } getFragAtPos(position, levelType, buffered) { const { fragments } = this; const keys = Object.keys(fragments); for (let i = keys.length; i--;) { const fragmentEntity = fragments[keys[i]]; if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && (!buffered || fragmentEntity.buffered)) { const frag = fragmentEntity.body; if (frag.start <= position && position <= frag.end) return frag; } } return null; } /** * Partial fragments effected by coded frame eviction will be removed * The browser will unload parts of the buffer to free up memory for new buffer data * Fragments will need to be reloaded when the buffer is freed up, removing partial fragments will allow them to reload(since there might be parts that are still playable) */ detectEvictedFragments(elementaryStream, timeRange, playlistType, appendedPart, removeAppending) { if (this.timeRanges) this.timeRanges[elementaryStream] = timeRange; const appendedPartSn = (appendedPart == null ? void 0 : appendedPart.fragment.sn) || -1; Object.keys(this.fragments).forEach((key) => { const fragmentEntity = this.fragments[key]; if (!fragmentEntity) return; if (appendedPartSn >= fragmentEntity.body.sn) return; if (!fragmentEntity.buffered && (!fragmentEntity.loaded || removeAppending)) { if (fragmentEntity.body.type === playlistType) this.removeFragment(fragmentEntity.body); return; } const esData = fragmentEntity.range[elementaryStream]; if (!esData) return; if (esData.time.length === 0) { this.removeFragment(fragmentEntity.body); return; } esData.time.some((time) => { const isNotBuffered = !this.isTimeBuffered(time.startPTS, time.endPTS, timeRange); if (isNotBuffered) this.removeFragment(fragmentEntity.body); return isNotBuffered; }); }); } /** * Checks if the fragment passed in is loaded in the buffer properly * Partially loaded fragments will be registered as a partial fragment */ detectPartialFragments(data) { const timeRanges = this.timeRanges; if (!timeRanges || data.frag.sn === "initSegment") return; const frag = data.frag; const fragKey = getFragmentKey(frag); const fragmentEntity = this.fragments[fragKey]; if (!fragmentEntity || fragmentEntity.buffered && frag.gap) return; const isFragHint = !frag.relurl; Object.keys(timeRanges).forEach((elementaryStream) => { const streamInfo = frag.elementaryStreams[elementaryStream]; if (!streamInfo) return; const timeRange = timeRanges[elementaryStream]; const partial = isFragHint || streamInfo.partial === true; fragmentEntity.range[elementaryStream] = this.getBufferedTimes(frag, data.part, partial, timeRange); }); fragmentEntity.loaded = null; if (Object.keys(fragmentEntity.range).length) { this.bufferedEnd(fragmentEntity, frag); if (!isPartial(fragmentEntity)) this.removeParts(frag.sn - 1, frag.type); } else this.removeFragment(fragmentEntity.body); } bufferedEnd(fragmentEntity, frag) { fragmentEntity.buffered = true; if (fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList) this.endListFragments[fragmentEntity.body.type] = fragmentEntity; } removeParts(snToKeep, levelType) { const activeParts = this.activePartLists[levelType]; if (!activeParts) return; this.activePartLists[levelType] = filterParts(activeParts, (part) => part.fragment.sn >= snToKeep); } fragBuffered(frag, force) { const fragKey = getFragmentKey(frag); let fragmentEntity = this.fragments[fragKey]; if (!fragmentEntity && force) { fragmentEntity = this.fragments[fragKey] = { body: frag, appendedPTS: null, loaded: null, buffered: false, range: Object.create(null) }; if (frag.gap) this.hasGaps = true; } if (fragmentEntity) { fragmentEntity.loaded = null; this.bufferedEnd(fragmentEntity, frag); } } getBufferedTimes(fragment, part, partial, timeRange) { const buffered = { time: [], partial }; const startPTS = fragment.start; const endPTS = fragment.end; const minEndPTS = fragment.minEndPTS || endPTS; const maxStartPTS = fragment.maxStartPTS || startPTS; for (let i = 0; i < timeRange.length; i++) { const startTime = timeRange.start(i) - this.bufferPadding; const endTime = timeRange.end(i) + this.bufferPadding; if (maxStartPTS >= startTime && minEndPTS <= endTime) { buffered.time.push({ startPTS: Math.max(startPTS, timeRange.start(i)), endPTS: Math.min(endPTS, timeRange.end(i)) }); break; } else if (startPTS < endTime && endPTS > startTime) { const start = Math.max(startPTS, timeRange.start(i)); const end = Math.min(endPTS, timeRange.end(i)); if (end > start) { buffered.partial = true; buffered.time.push({ startPTS: start, endPTS: end }); } } else if (endPTS <= startTime) break; } return buffered; } /** * Gets the partial fragment for a certain time */ getPartialFragment(time) { let bestFragment = null; let timePadding; let startTime; let endTime; let bestOverlap = 0; const { bufferPadding, fragments } = this; Object.keys(fragments).forEach((key) => { const fragmentEntity = fragments[key]; if (!fragmentEntity) return; if (isPartial(fragmentEntity)) { startTime = fragmentEntity.body.start - bufferPadding; endTime = fragmentEntity.body.end + bufferPadding; if (time >= startTime && time <= endTime) { timePadding = Math.min(time - startTime, endTime - time); if (bestOverlap <= timePadding) { bestFragment = fragmentEntity.body; bestOverlap = timePadding; } } } }); return bestFragment; } isEndListAppended(type) { const lastFragmentEntity = this.endListFragments[type]; return lastFragmentEntity !== void 0 && (lastFragmentEntity.buffered || isPartial(lastFragmentEntity)); } getState(fragment) { const fragKey = getFragmentKey(fragment); const fragmentEntity = this.fragments[fragKey]; if (fragmentEntity) if (!fragmentEntity.buffered) return FragmentState.APPENDING; else if (isPartial(fragmentEntity)) return FragmentState.PARTIAL; else return FragmentState.OK; return FragmentState.NOT_LOADED; } isTimeBuffered(startPTS, endPTS, timeRange) { let startTime; let endTime; for (let i = 0; i < timeRange.length; i++) { startTime = timeRange.start(i) - this.bufferPadding; endTime = timeRange.end(i) + this.bufferPadding; if (startPTS >= startTime && endPTS <= endTime) return true; if (endPTS <= startTime) return false; } return false; } onManifestLoading() { this.removeAllFragments(); } onFragLoaded(event, data) { if (data.frag.sn === "initSegment" || data.frag.bitrateTest) return; const frag = data.frag; const loaded = data.part ? null : data; const fragKey = getFragmentKey(frag); this.fragments[fragKey] = { body: frag, appendedPTS: null, loaded, buffered: false, range: Object.create(null) }; } onBufferAppended(event, data) { const { frag, part, timeRanges, type } = data; if (frag.sn === "initSegment") return; const playlistType = frag.type; if (part) { let activeParts = this.activePartLists[playlistType]; if (!activeParts) this.activePartLists[playlistType] = activeParts = []; activeParts.push(part); } this.timeRanges = timeRanges; const timeRange = timeRanges[type]; this.detectEvictedFragments(type, timeRange, playlistType, part); } onFragBuffered(event, data) { this.detectPartialFragments(data); } hasFragment(fragment) { const fragKey = getFragmentKey(fragment); return !!this.fragments[fragKey]; } hasFragments(type) { const { fragments } = this; const keys = Object.keys(fragments); if (!type) return keys.length > 0; for (let i = keys.length; i--;) { const fragmentEntity = fragments[keys[i]]; if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === type) return true; } return false; } hasParts(type) { var _this$activePartLists; return !!((_this$activePartLists = this.activePartLists[type]) != null && _this$activePartLists.length); } removeFragmentsInRange(start, end, playlistType, withGapOnly, unbufferedOnly) { if (withGapOnly && !this.hasGaps) return; Object.keys(this.fragments).forEach((key) => { const fragmentEntity = this.fragments[key]; if (!fragmentEntity) return; const frag = fragmentEntity.body; if (frag.type !== playlistType || withGapOnly && !frag.gap) return; if (frag.start < end && frag.end > start && (fragmentEntity.buffered || unbufferedOnly)) this.removeFragment(frag); }); } removeFragment(fragment) { const fragKey = getFragmentKey(fragment); fragment.clearElementaryStreamInfo(); const activeParts = this.activePartLists[fragment.type]; if (activeParts) { const snToRemove = fragment.sn; this.activePartLists[fragment.type] = filterParts(activeParts, (part) => part.fragment.sn !== snToRemove); } delete this.fragments[fragKey]; if (fragment.endList) delete this.endListFragments[fragment.type]; } removeAllFragments() { var _this$hls; this.fragments = Object.create(null); this.endListFragments = Object.create(null); this.activePartLists = Object.create(null); this.hasGaps = false; const partlist = (_this$hls = this.hls) == null || (_this$hls = _this$hls.latestLevelDetails) == null ? void 0 : _this$hls.partList; if (partlist) partlist.forEach((part) => part.clearElementaryStreamInfo()); } }; function isPartial(fragmentEntity) { var _fragmentEntity$range, _fragmentEntity$range2, _fragmentEntity$range3; return fragmentEntity.buffered && !!(fragmentEntity.body.gap || (_fragmentEntity$range = fragmentEntity.range.video) != null && _fragmentEntity$range.partial || (_fragmentEntity$range2 = fragmentEntity.range.audio) != null && _fragmentEntity$range2.partial || (_fragmentEntity$range3 = fragmentEntity.range.audiovideo) != null && _fragmentEntity$range3.partial); } function getFragmentKey(fragment) { return `${fragment.type}_${fragment.level}_${fragment.sn}`; } function filterParts(partList, predicate) { return partList.filter((part) => { const keep = predicate(part); if (!keep) part.clearElementaryStreamInfo(); return keep; }); } var DecrypterAesMode = { cbc: 0, ctr: 1 }; var AESCrypto = class { constructor(subtle, iv, aesMode) { this.subtle = void 0; this.aesIV = void 0; this.aesMode = void 0; this.subtle = subtle; this.aesIV = iv; this.aesMode = aesMode; } decrypt(data, key) { switch (this.aesMode) { case DecrypterAesMode.cbc: return this.subtle.decrypt({ name: "AES-CBC", iv: this.aesIV }, key, data); case DecrypterAesMode.ctr: return this.subtle.decrypt({ name: "AES-CTR", counter: this.aesIV, length: 64 }, key, data); default: throw new Error(`[AESCrypto] invalid aes mode ${this.aesMode}`); } } }; function removePadding(array) { const outputBytes = array.byteLength; const paddingBytes = outputBytes && new DataView(array.buffer).getUint8(outputBytes - 1); if (paddingBytes) return array.slice(0, outputBytes - paddingBytes); return array; } var AESDecryptor = class { constructor() { this.rcon = [ 0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 ]; this.subMix = [ new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256) ]; this.invSubMix = [ new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256) ]; this.sBox = new Uint32Array(256); this.invSBox = new Uint32Array(256); this.key = new Uint32Array(0); this.ksRows = 0; this.keySize = 0; this.keySchedule = void 0; this.invKeySchedule = void 0; this.initTable(); } uint8ArrayToUint32Array_(arrayBuffer) { const view = new DataView(arrayBuffer); const newArray = new Uint32Array(4); for (let i = 0; i < 4; i++) newArray[i] = view.getUint32(i * 4); return newArray; } initTable() { const sBox = this.sBox; const invSBox = this.invSBox; const subMix = this.subMix; const subMix0 = subMix[0]; const subMix1 = subMix[1]; const subMix2 = subMix[2]; const subMix3 = subMix[3]; const invSubMix = this.invSubMix; const invSubMix0 = invSubMix[0]; const invSubMix1 = invSubMix[1]; const invSubMix2 = invSubMix[2]; const invSubMix3 = invSubMix[3]; const d = new Uint32Array(256); let x = 0; let xi = 0; let i = 0; for (i = 0; i < 256; i++) if (i < 128) d[i] = i << 1; else d[i] = i << 1 ^ 283; for (i = 0; i < 256; i++) { let sx = xi ^ xi << 1 ^ xi << 2 ^ xi << 3 ^ xi << 4; sx = sx >>> 8 ^ sx & 255 ^ 99; sBox[x] = sx; invSBox[sx] = x; const x2 = d[x]; const x4 = d[x2]; const x8 = d[x4]; let t = d[sx] * 257 ^ sx * 16843008; subMix0[x] = t << 24 | t >>> 8; subMix1[x] = t << 16 | t >>> 16; subMix2[x] = t << 8 | t >>> 24; subMix3[x] = t; t = x8 * 16843009 ^ x4 * 65537 ^ x2 * 257 ^ x * 16843008; invSubMix0[sx] = t << 24 | t >>> 8; invSubMix1[sx] = t << 16 | t >>> 16; invSubMix2[sx] = t << 8 | t >>> 24; invSubMix3[sx] = t; if (!x) x = xi = 1; else { x = x2 ^ d[d[d[x8 ^ x2]]]; xi ^= d[d[xi]]; } } } expandKey(keyBuffer) { const key = this.uint8ArrayToUint32Array_(keyBuffer); let sameKey = true; let offset = 0; while (offset < key.length && sameKey) { sameKey = key[offset] === this.key[offset]; offset++; } if (sameKey) return; this.key = key; const keySize = this.keySize = key.length; if (keySize !== 4 && keySize !== 6 && keySize !== 8) throw new Error("Invalid aes key size=" + keySize); const ksRows = this.ksRows = (keySize + 6 + 1) * 4; let ksRow; let invKsRow; const keySchedule = this.keySchedule = new Uint32Array(ksRows); const invKeySchedule = this.invKeySchedule = new Uint32Array(ksRows); const sbox = this.sBox; const rcon = this.rcon; const invSubMix = this.invSubMix; const invSubMix0 = invSubMix[0]; const invSubMix1 = invSubMix[1]; const invSubMix2 = invSubMix[2]; const invSubMix3 = invSubMix[3]; let prev; let t; for (ksRow = 0; ksRow < ksRows; ksRow++) { if (ksRow < keySize) { prev = keySchedule[ksRow] = key[ksRow]; continue; } t = prev; if (ksRow % keySize === 0) { t = t << 8 | t >>> 24; t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 255] << 16 | sbox[t >>> 8 & 255] << 8 | sbox[t & 255]; t ^= rcon[ksRow / keySize | 0] << 24; } else if (keySize > 6 && ksRow % keySize === 4) t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 255] << 16 | sbox[t >>> 8 & 255] << 8 | sbox[t & 255]; keySchedule[ksRow] = prev = (keySchedule[ksRow - keySize] ^ t) >>> 0; } for (invKsRow = 0; invKsRow < ksRows; invKsRow++) { ksRow = ksRows - invKsRow; if (invKsRow & 3) t = keySchedule[ksRow]; else t = keySchedule[ksRow - 4]; if (invKsRow < 4 || ksRow <= 4) invKeySchedule[invKsRow] = t; else invKeySchedule[invKsRow] = invSubMix0[sbox[t >>> 24]] ^ invSubMix1[sbox[t >>> 16 & 255]] ^ invSubMix2[sbox[t >>> 8 & 255]] ^ invSubMix3[sbox[t & 255]]; invKeySchedule[invKsRow] = invKeySchedule[invKsRow] >>> 0; } } networkToHostOrderSwap(word) { return word << 24 | (word & 65280) << 8 | (word & 16711680) >> 8 | word >>> 24; } decrypt(inputArrayBuffer, offset, aesIV) { const nRounds = this.keySize + 6; const invKeySchedule = this.invKeySchedule; const invSBOX = this.invSBox; const invSubMix = this.invSubMix; const invSubMix0 = invSubMix[0]; const invSubMix1 = invSubMix[1]; const invSubMix2 = invSubMix[2]; const invSubMix3 = invSubMix[3]; const initVector = this.uint8ArrayToUint32Array_(aesIV); let initVector0 = initVector[0]; let initVector1 = initVector[1]; let initVector2 = initVector[2]; let initVector3 = initVector[3]; const inputInt32 = new Int32Array(inputArrayBuffer); const outputInt32 = new Int32Array(inputInt32.length); let t0, t1, t2, t3; let s0, s1, s2, s3; let inputWords0, inputWords1, inputWords2, inputWords3; let ksRow, i; const swapWord = this.networkToHostOrderSwap; while (offset < inputInt32.length) { inputWords0 = swapWord(inputInt32[offset]); inputWords1 = swapWord(inputInt32[offset + 1]); inputWords2 = swapWord(inputInt32[offset + 2]); inputWords3 = swapWord(inputInt32[offset + 3]); s0 = inputWords0 ^ invKeySchedule[0]; s1 = inputWords3 ^ invKeySchedule[1]; s2 = inputWords2 ^ invKeySchedule[2]; s3 = inputWords1 ^ invKeySchedule[3]; ksRow = 4; for (i = 1; i < nRounds; i++) { t0 = invSubMix0[s0 >>> 24] ^ invSubMix1[s1 >> 16 & 255] ^ invSubMix2[s2 >> 8 & 255] ^ invSubMix3[s3 & 255] ^ invKeySchedule[ksRow]; t1 = invSubMix0[s1 >>> 24] ^ invSubMix1[s2 >> 16 & 255] ^ invSubMix2[s3 >> 8 & 255] ^ invSubMix3[s0 & 255] ^ invKeySchedule[ksRow + 1]; t2 = invSubMix0[s2 >>> 24] ^ invSubMix1[s3 >> 16 & 255] ^ invSubMix2[s0 >> 8 & 255] ^ invSubMix3[s1 & 255] ^ invKeySchedule[ksRow + 2]; t3 = invSubMix0[s3 >>> 24] ^ invSubMix1[s0 >> 16 & 255] ^ invSubMix2[s1 >> 8 & 255] ^ invSubMix3[s2 & 255] ^ invKeySchedule[ksRow + 3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; ksRow = ksRow + 4; } t0 = invSBOX[s0 >>> 24] << 24 ^ invSBOX[s1 >> 16 & 255] << 16 ^ invSBOX[s2 >> 8 & 255] << 8 ^ invSBOX[s3 & 255] ^ invKeySchedule[ksRow]; t1 = invSBOX[s1 >>> 24] << 24 ^ invSBOX[s2 >> 16 & 255] << 16 ^ invSBOX[s3 >> 8 & 255] << 8 ^ invSBOX[s0 & 255] ^ invKeySchedule[ksRow + 1]; t2 = invSBOX[s2 >>> 24] << 24 ^ invSBOX[s3 >> 16 & 255] << 16 ^ invSBOX[s0 >> 8 & 255] << 8 ^ invSBOX[s1 & 255] ^ invKeySchedule[ksRow + 2]; t3 = invSBOX[s3 >>> 24] << 24 ^ invSBOX[s0 >> 16 & 255] << 16 ^ invSBOX[s1 >> 8 & 255] << 8 ^ invSBOX[s2 & 255] ^ invKeySchedule[ksRow + 3]; outputInt32[offset] = swapWord(t0 ^ initVector0); outputInt32[offset + 1] = swapWord(t3 ^ initVector1); outputInt32[offset + 2] = swapWord(t2 ^ initVector2); outputInt32[offset + 3] = swapWord(t1 ^ initVector3); initVector0 = inputWords0; initVector1 = inputWords1; initVector2 = inputWords2; initVector3 = inputWords3; offset = offset + 4; } return outputInt32.buffer; } }; var FastAESKey = class { constructor(subtle, key, aesMode) { this.subtle = void 0; this.key = void 0; this.aesMode = void 0; this.subtle = subtle; this.key = key; this.aesMode = aesMode; } expandKey() { const subtleAlgoName = getSubtleAlgoName(this.aesMode); return this.subtle.importKey("raw", this.key, { name: subtleAlgoName }, false, ["encrypt", "decrypt"]); } }; function getSubtleAlgoName(aesMode) { switch (aesMode) { case DecrypterAesMode.cbc: return "AES-CBC"; case DecrypterAesMode.ctr: return "AES-CTR"; default: throw new Error(`[FastAESKey] invalid aes mode ${aesMode}`); } } var CHUNK_SIZE = 16; var Decrypter = class { constructor(config, { removePKCS7Padding = true } = {}) { this.logEnabled = true; this.removePKCS7Padding = void 0; this.subtle = null; this.softwareDecrypter = null; this.key = null; this.fastAesKey = null; this.remainderData = null; this.currentIV = null; this.currentResult = null; this.useSoftware = void 0; this.enableSoftwareAES = void 0; this.enableSoftwareAES = config.enableSoftwareAES; this.removePKCS7Padding = removePKCS7Padding; if (removePKCS7Padding) try { const browserCrypto = self.crypto; if (browserCrypto) this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; } catch (e) {} this.useSoftware = !this.subtle; } destroy() { this.subtle = null; this.softwareDecrypter = null; this.key = null; this.fastAesKey = null; this.remainderData = null; this.currentIV = null; this.currentResult = null; } isSync() { return this.useSoftware; } flush() { const { currentResult, remainderData } = this; if (!currentResult || remainderData) { this.reset(); return null; } const data = new Uint8Array(currentResult); this.reset(); if (this.removePKCS7Padding) return removePadding(data); return data; } reset() { this.currentResult = null; this.currentIV = null; this.remainderData = null; if (this.softwareDecrypter) this.softwareDecrypter = null; } decrypt(data, key, iv, aesMode) { if (this.useSoftware) return new Promise((resolve, reject) => { const dataView = ArrayBuffer.isView(data) ? data : new Uint8Array(data); this.softwareDecrypt(dataView, key, iv, aesMode); const decryptResult = this.flush(); if (decryptResult) resolve(decryptResult.buffer); else reject(/* @__PURE__ */ new Error("[softwareDecrypt] Failed to decrypt data")); }); return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode); } softwareDecrypt(data, key, iv, aesMode) { const { currentIV, currentResult, remainderData } = this; if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) { logger.warn("SoftwareDecrypt: can only handle AES-128-CBC"); return null; } this.logOnce("JS AES decrypt"); if (remainderData) { data = appendUint8Array(remainderData, data); this.remainderData = null; } const currentChunk = this.getValidChunk(data); if (!currentChunk.length) return null; if (currentIV) iv = currentIV; let softwareDecrypter = this.softwareDecrypter; if (!softwareDecrypter) softwareDecrypter = this.softwareDecrypter = new AESDecryptor(); softwareDecrypter.expandKey(key); const result = currentResult; this.currentResult = softwareDecrypter.decrypt(currentChunk.buffer, 0, iv); this.currentIV = currentChunk.slice(-16).buffer; if (!result) return null; return result; } webCryptoDecrypt(data, key, iv, aesMode) { if (this.key !== key || !this.fastAesKey) { if (!this.subtle) return Promise.resolve(this.onWebCryptoError(data, key, iv, aesMode)); this.key = key; this.fastAesKey = new FastAESKey(this.subtle, key, aesMode); } return this.fastAesKey.expandKey().then((aesKey) => { if (!this.subtle) return Promise.reject(/* @__PURE__ */ new Error("web crypto not initialized")); this.logOnce("WebCrypto AES decrypt"); return new AESCrypto(this.subtle, new Uint8Array(iv), aesMode).decrypt(data.buffer, aesKey); }).catch((err) => { logger.warn(`[decrypter]: WebCrypto Error, disable WebCrypto API, ${err.name}: ${err.message}`); return this.onWebCryptoError(data, key, iv, aesMode); }); } onWebCryptoError(data, key, iv, aesMode) { const enableSoftwareAES = this.enableSoftwareAES; if (enableSoftwareAES) { this.useSoftware = true; this.logEnabled = true; this.softwareDecrypt(data, key, iv, aesMode); const decryptResult = this.flush(); if (decryptResult) return decryptResult.buffer; } throw new Error("WebCrypto" + (enableSoftwareAES ? " and softwareDecrypt" : "") + ": failed to decrypt data"); } getValidChunk(data) { let currentChunk = data; const splitPoint = data.length - data.length % CHUNK_SIZE; if (splitPoint !== data.length) { currentChunk = data.slice(0, splitPoint); this.remainderData = data.slice(splitPoint); } return currentChunk; } logOnce(msg) { if (!this.logEnabled) return; logger.log(`[decrypter]: ${msg}`); this.logEnabled = false; } }; var MIN_CHUNK_SIZE = Math.pow(2, 17); var FragmentLoader = class { constructor(config) { this.config = void 0; this.loader = null; this.partLoadTimeout = -1; this.config = config; } destroy() { if (this.loader) { this.loader.destroy(); this.loader = null; } } abort() { if (this.loader) this.loader.abort(); } load(frag, onProgress) { const url = frag.url; if (!url) return Promise.reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag, error: /* @__PURE__ */ new Error(`Fragment does not have a ${url ? "part list" : "url"}`), networkDetails: null })); this.abort(); const config = this.config; const FragmentILoader = config.fLoader; const DefaultILoader = config.loader; return new Promise((resolve, reject) => { if (this.loader) this.loader.destroy(); if (frag.gap) if (frag.tagList.some((tags) => tags[0] === "GAP")) { reject(createGapLoadError(frag)); return; } else frag.gap = false; const loader = this.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config); const loaderContext = createLoaderContext(frag); frag.loader = loader; const loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default); const loaderConfig = { loadPolicy, timeout: loadPolicy.maxLoadTimeMs, maxRetry: 0, retryDelay: 0, maxRetryDelay: 0, highWaterMark: frag.sn === "initSegment" ? Infinity : MIN_CHUNK_SIZE }; frag.stats = loader.stats; const callbacks = { onSuccess: (response, stats, context, networkDetails) => { this.resetLoader(frag, loader); let payload = response.data; if (context.resetIV && frag.decryptdata) { frag.decryptdata.iv = new Uint8Array(payload.slice(0, 16)); payload = payload.slice(16); } resolve({ frag, part: null, payload, networkDetails }); }, onError: (response, context, networkDetails, stats) => { this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag, response: _objectSpread2({ url, data: void 0 }, response), error: /* @__PURE__ */ new Error(`HTTP Error ${response.code} ${response.text}`), networkDetails, stats })); }, onAbort: (stats, context, networkDetails) => { this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.INTERNAL_ABORTED, fatal: false, frag, error: /* @__PURE__ */ new Error("Aborted"), networkDetails, stats })); }, onTimeout: (stats, context, networkDetails) => { this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_TIMEOUT, fatal: false, frag, error: /* @__PURE__ */ new Error(`Timeout after ${loaderConfig.timeout}ms`), networkDetails, stats })); } }; if (onProgress) callbacks.onProgress = (stats, context, data, networkDetails) => onProgress({ frag, part: null, payload: data, networkDetails }); loader.load(loaderContext, loaderConfig, callbacks); }); } loadPart(frag, part, onProgress) { this.abort(); const config = this.config; const FragmentILoader = config.fLoader; const DefaultILoader = config.loader; return new Promise((resolve, reject) => { if (this.loader) this.loader.destroy(); if (frag.gap || part.gap) { reject(createGapLoadError(frag, part)); return; } const loader = this.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config); const loaderContext = createLoaderContext(frag, part); frag.loader = loader; const loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default); const loaderConfig = { loadPolicy, timeout: loadPolicy.maxLoadTimeMs, maxRetry: 0, retryDelay: 0, maxRetryDelay: 0, highWaterMark: MIN_CHUNK_SIZE }; part.stats = loader.stats; loader.load(loaderContext, loaderConfig, { onSuccess: (response, stats, context, networkDetails) => { this.resetLoader(frag, loader); this.updateStatsFromPart(frag, part); const partLoadedData = { frag, part, payload: response.data, networkDetails }; onProgress(partLoadedData); resolve(partLoadedData); }, onError: (response, context, networkDetails, stats) => { this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag, part, response: _objectSpread2({ url: loaderContext.url, data: void 0 }, response), error: /* @__PURE__ */ new Error(`HTTP Error ${response.code} ${response.text}`), networkDetails, stats })); }, onAbort: (stats, context, networkDetails) => { frag.stats.aborted = part.stats.aborted; this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.INTERNAL_ABORTED, fatal: false, frag, part, error: /* @__PURE__ */ new Error("Aborted"), networkDetails, stats })); }, onTimeout: (stats, context, networkDetails) => { this.resetLoader(frag, loader); reject(new LoadError({ type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_TIMEOUT, fatal: false, frag, part, error: /* @__PURE__ */ new Error(`Timeout after ${loaderConfig.timeout}ms`), networkDetails, stats })); } }); }); } updateStatsFromPart(frag, part) { const fragStats = frag.stats; const partStats = part.stats; const partTotal = partStats.total; fragStats.loaded += partStats.loaded; if (partTotal) { const estTotalParts = Math.round(frag.duration / part.duration); const estLoadedParts = Math.min(Math.round(fragStats.loaded / partTotal), estTotalParts); const estRemainingBytes = (estTotalParts - estLoadedParts) * Math.round(fragStats.loaded / estLoadedParts); fragStats.total = fragStats.loaded + estRemainingBytes; } else fragStats.total = Math.max(fragStats.loaded, fragStats.total); const fragLoading = fragStats.loading; const partLoading = partStats.loading; if (fragLoading.start) fragLoading.first += partLoading.first - partLoading.start; else { fragLoading.start = partLoading.start; fragLoading.first = partLoading.first; } fragLoading.end = partLoading.end; } resetLoader(frag, loader) { frag.loader = null; if (this.loader === loader) { self.clearTimeout(this.partLoadTimeout); this.loader = null; } loader.destroy(); } }; function createLoaderContext(frag, part = null) { const segment = part || frag; const loaderContext = { frag, part, responseType: "arraybuffer", url: segment.url, headers: {}, rangeStart: 0, rangeEnd: 0 }; const start = segment.byteRangeStartOffset; const end = segment.byteRangeEndOffset; if (isFiniteNumber(start) && isFiniteNumber(end)) { var _frag$decryptdata; let byteRangeStart = start; let byteRangeEnd = end; if (frag.sn === "initSegment" && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) { const fragmentLen = end - start; if (fragmentLen % 16) byteRangeEnd = end + (16 - fragmentLen % 16); if (start !== 0) { loaderContext.resetIV = true; byteRangeStart = start - 16; } } loaderContext.rangeStart = byteRangeStart; loaderContext.rangeEnd = byteRangeEnd; } return loaderContext; } function createGapLoadError(frag, part) { const error = /* @__PURE__ */ new Error(`GAP ${frag.gap ? "tag" : "attribute"} found`); const errorData = { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_GAP, fatal: false, frag, error, networkDetails: null }; if (part) errorData.part = part; (part ? part : frag).stats.aborted = true; return new LoadError(errorData); } function isMethodFullSegmentAesCbc(method) { return method === "AES-128" || method === "AES-256"; } var LoadError = class extends Error { constructor(data) { super(data.error.message); this.data = void 0; this.data = data; } }; /** * @ignore * Sub-class specialization of EventHandler base class. * * TaskLoop allows to schedule a task function being called (optionnaly repeatedly) on the main loop, * scheduled asynchroneously, avoiding recursive calls in the same tick. * * The task itself is implemented in `doTick`. It can be requested and called for single execution * using the `tick` method. * * It will be assured that the task execution method (`tick`) only gets called once per main loop "tick", * no matter how often it gets requested for execution. Execution in further ticks will be scheduled accordingly. * * If further execution requests have already been scheduled on the next tick, it can be checked with `hasNextTick`, * and cancelled with `clearNextTick`. * * The task can be scheduled as an interval repeatedly with a period as parameter (see `setInterval`, `clearInterval`). * * Sub-classes need to implement the `doTick` method which will effectively have the task execution routine. * * Further explanations: * * The baseclass has a `tick` method that will schedule the doTick call. It may be called synchroneously * only for a stack-depth of one. On re-entrant calls, sub-sequent calls are scheduled for next main loop ticks. * * When the task execution (`tick` method) is called in re-entrant way this is detected and * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo). */ var TaskLoop = class extends Logger { constructor(label, logger) { super(label, logger); this._boundTick = void 0; this._tickTimer = null; this._tickInterval = null; this._tickCallCount = 0; this._boundTick = this.tick.bind(this); } destroy() { this.onHandlerDestroying(); this.onHandlerDestroyed(); } onHandlerDestroying() { this.clearNextTick(); this.clearInterval(); } onHandlerDestroyed() {} hasInterval() { return !!this._tickInterval; } hasNextTick() { return !!this._tickTimer; } /** * @param millis - Interval time (ms) * @eturns True when interval has been scheduled, false when already scheduled (no effect) */ setInterval(millis) { if (!this._tickInterval) { this._tickCallCount = 0; this._tickInterval = self.setInterval(this._boundTick, millis); return true; } return false; } /** * @returns True when interval was cleared, false when none was set (no effect) */ clearInterval() { if (this._tickInterval) { self.clearInterval(this._tickInterval); this._tickInterval = null; return true; } return false; } /** * @returns True when timeout was cleared, false when none was set (no effect) */ clearNextTick() { if (this._tickTimer) { self.clearTimeout(this._tickTimer); this._tickTimer = null; return true; } return false; } /** * Will call the subclass doTick implementation in this main loop tick * or in the next one (via setTimeout(,0)) in case it has already been called * in this tick (in case this is a re-entrant call). */ tick() { this._tickCallCount++; if (this._tickCallCount === 1) { this.doTick(); if (this._tickCallCount > 1) this.tickImmediate(); this._tickCallCount = 0; } } tickImmediate() { this.clearNextTick(); this._tickTimer = self.setTimeout(this._boundTick, 0); } /** * For subclass to implement task logic * @abstract */ doTick() {} }; var ChunkMetadata = class { constructor(level, sn, id, size = 0, part = -1, partial = false) { this.level = void 0; this.sn = void 0; this.part = void 0; this.id = void 0; this.size = void 0; this.partial = void 0; this.transmuxing = getNewPerformanceTiming(); this.buffering = { audio: getNewPerformanceTiming(), video: getNewPerformanceTiming(), audiovideo: getNewPerformanceTiming() }; this.level = level; this.sn = sn; this.id = id; this.size = size; this.part = part; this.partial = partial; } }; function getNewPerformanceTiming() { return { start: 0, executeStart: 0, executeEnd: 0, end: 0 }; } /** * Provides methods dealing with buffer length retrieval for example. * * In general, a helper around HTML5 MediaElement TimeRanges gathered from `buffered` property. * * Also @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered */ var noopBuffered = { length: 0, start: () => 0, end: () => 0 }; var BufferHelper = class BufferHelper { /** * Return true if `media`'s buffered include `position` */ static isBuffered(media, position) { if (media) { const buffered = BufferHelper.getBuffered(media); for (let i = buffered.length; i--;) if (position >= buffered.start(i) && position <= buffered.end(i)) return true; } return false; } static bufferedRanges(media) { if (media) { const timeRanges = BufferHelper.getBuffered(media); return BufferHelper.timeRangesToArray(timeRanges); } return []; } static timeRangesToArray(timeRanges) { const buffered = []; for (let i = 0; i < timeRanges.length; i++) buffered.push({ start: timeRanges.start(i), end: timeRanges.end(i) }); return buffered; } static bufferInfo(media, pos, maxHoleDuration) { if (media) { const buffered = BufferHelper.bufferedRanges(media); if (buffered.length) return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration); } return { len: 0, start: pos, end: pos, bufferedIndex: -1 }; } static bufferedInfo(buffered, pos, maxHoleDuration) { pos = Math.max(0, pos); if (buffered.length > 1) buffered.sort((a, b) => a.start - b.start || b.end - a.end); let bufferedIndex = -1; let buffered2 = []; if (maxHoleDuration) for (let i = 0; i < buffered.length; i++) { if (pos >= buffered[i].start && pos <= buffered[i].end) bufferedIndex = i; const buf2len = buffered2.length; if (buf2len) { const buf2end = buffered2[buf2len - 1].end; if (buffered[i].start - buf2end < maxHoleDuration) { if (buffered[i].end > buf2end) buffered2[buf2len - 1].end = buffered[i].end; } else buffered2.push(buffered[i]); } else buffered2.push(buffered[i]); } else buffered2 = buffered; let bufferLen = 0; let nextStart; let bufferStart = pos; let bufferEnd = pos; for (let i = 0; i < buffered2.length; i++) { const start = buffered2[i].start; const end = buffered2[i].end; if (bufferedIndex === -1 && pos >= start && pos <= end) bufferedIndex = i; if (pos + maxHoleDuration >= start && pos < end) { bufferStart = start; bufferEnd = end; bufferLen = bufferEnd - pos; } else if (pos + maxHoleDuration < start) { nextStart = start; break; } } return { len: bufferLen, start: bufferStart || 0, end: bufferEnd || 0, nextStart, buffered, bufferedIndex }; } /** * Safe method to get buffered property. * SourceBuffer.buffered may throw if SourceBuffer is removed from it's MediaSource */ static getBuffered(media) { try { return media.buffered || noopBuffered; } catch (e) { logger.log("failed to get media.buffered", e); return noopBuffered; } } }; var VARIABLE_REPLACEMENT_REGEX = /\{\$([a-zA-Z0-9-_]+)\}/g; function hasVariableReferences(str) { return VARIABLE_REPLACEMENT_REGEX.test(str); } function substituteVariables(parsed, value) { if (parsed.variableList !== null || parsed.hasVariableRefs) { const variableList = parsed.variableList; return value.replace(VARIABLE_REPLACEMENT_REGEX, (variableReference) => { const variableName = variableReference.substring(2, variableReference.length - 1); const variableValue = variableList == null ? void 0 : variableList[variableName]; if (variableValue === void 0) { parsed.playlistParsingError || (parsed.playlistParsingError = /* @__PURE__ */ new Error(`Missing preceding EXT-X-DEFINE tag for Variable Reference: "${variableName}"`)); return variableReference; } return variableValue; }); } return value; } function addVariableDefinition(parsed, attr, parentUrl) { let variableList = parsed.variableList; if (!variableList) parsed.variableList = variableList = {}; let NAME; let VALUE; if ("QUERYPARAM" in attr) { NAME = attr.QUERYPARAM; try { const searchParams = new self.URL(parentUrl).searchParams; if (searchParams.has(NAME)) VALUE = searchParams.get(NAME); else throw new Error(`"${NAME}" does not match any query parameter in URI: "${parentUrl}"`); } catch (error) { parsed.playlistParsingError || (parsed.playlistParsingError = /* @__PURE__ */ new Error(`EXT-X-DEFINE QUERYPARAM: ${error.message}`)); } } else { NAME = attr.NAME; VALUE = attr.VALUE; } if (NAME in variableList) parsed.playlistParsingError || (parsed.playlistParsingError = /* @__PURE__ */ new Error(`EXT-X-DEFINE duplicate Variable Name declarations: "${NAME}"`)); else variableList[NAME] = VALUE || ""; } function importVariableDefinition(parsed, attr, sourceVariableList) { const IMPORT = attr.IMPORT; if (sourceVariableList && IMPORT in sourceVariableList) { let variableList = parsed.variableList; if (!variableList) parsed.variableList = variableList = {}; variableList[IMPORT] = sourceVariableList[IMPORT]; } else parsed.playlistParsingError || (parsed.playlistParsingError = /* @__PURE__ */ new Error(`EXT-X-DEFINE IMPORT attribute not found in Multivariant Playlist: "${IMPORT}"`)); } var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/; var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g; var AttrList = class AttrList { constructor(attrs, parsed) { if (typeof attrs === "string") attrs = AttrList.parseAttrList(attrs, parsed); _extends(this, attrs); } get clientAttrs() { return Object.keys(this).filter((attr) => attr.substring(0, 2) === "X-"); } decimalInteger(attrName) { const intValue = parseInt(this[attrName], 10); if (intValue > Number.MAX_SAFE_INTEGER) return Infinity; return intValue; } hexadecimalInteger(attrName) { if (this[attrName]) { let stringValue = (this[attrName] || "0x").slice(2); stringValue = (stringValue.length & 1 ? "0" : "") + stringValue; const value = new Uint8Array(stringValue.length / 2); for (let i = 0; i < stringValue.length / 2; i++) value[i] = parseInt(stringValue.slice(i * 2, i * 2 + 2), 16); return value; } return null; } hexadecimalIntegerAsNumber(attrName) { const intValue = parseInt(this[attrName], 16); if (intValue > Number.MAX_SAFE_INTEGER) return Infinity; return intValue; } decimalFloatingPoint(attrName) { return parseFloat(this[attrName]); } optionalFloat(attrName, defaultValue) { const value = this[attrName]; return value ? parseFloat(value) : defaultValue; } enumeratedString(attrName) { return this[attrName]; } enumeratedStringList(attrName, dict) { const attrValue = this[attrName]; return (attrValue ? attrValue.split(/[ ,]+/) : []).reduce((result, identifier) => { result[identifier.toLowerCase()] = true; return result; }, dict); } bool(attrName) { return this[attrName] === "YES"; } decimalResolution(attrName) { const res = DECIMAL_RESOLUTION_REGEX.exec(this[attrName]); if (res === null) return; return { width: parseInt(res[1], 10), height: parseInt(res[2], 10) }; } static parseAttrList(input, parsed) { let match; const attrs = {}; const quote = "\""; ATTR_LIST_REGEX.lastIndex = 0; while ((match = ATTR_LIST_REGEX.exec(input)) !== null) { const name = match[1].trim(); let value = match[2]; const quotedString = value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1; let hexadecimalSequence = false; if (quotedString) value = value.slice(1, -1); else switch (name) { case "IV": case "SCTE35-CMD": case "SCTE35-IN": case "SCTE35-OUT": hexadecimalSequence = true; } if (parsed && (quotedString || hexadecimalSequence)) value = substituteVariables(parsed, value); else if (!hexadecimalSequence && !quotedString) switch (name) { case "CLOSED-CAPTIONS": if (value === "NONE") break; case "ALLOWED-CPC": case "CLASS": case "ASSOC-LANGUAGE": case "AUDIO": case "BYTERANGE": case "CHANNELS": case "CHARACTERISTICS": case "CODECS": case "DATA-ID": case "END-DATE": case "GROUP-ID": case "ID": case "IMPORT": case "INSTREAM-ID": case "KEYFORMAT": case "KEYFORMATVERSIONS": case "LANGUAGE": case "NAME": case "PATHWAY-ID": case "QUERYPARAM": case "RECENTLY-REMOVED-DATERANGES": case "SERVER-URI": case "STABLE-RENDITION-ID": case "STABLE-VARIANT-ID": case "START-DATE": case "SUBTITLES": case "SUPPLEMENTAL-CODECS": case "URI": case "VALUE": case "VIDEO": case "X-ASSET-LIST": case "X-ASSET-URI": logger.warn(`${input}: attribute ${name} is missing quotes`); } attrs[name] = value; } return attrs; } }; var CLASS_INTERSTITIAL = "com.apple.hls.interstitial"; function isDateRangeCueAttribute(attrName) { return attrName !== "ID" && attrName !== "CLASS" && attrName !== "CUE" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT"; } function isSCTE35Attribute(attrName) { return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN" || attrName === "SCTE35-CMD"; } var DateRange = class { constructor(dateRangeAttr, dateRangeWithSameId, tagCount = 0) { var _dateRangeWithSameId$; this.attr = void 0; this.tagAnchor = void 0; this.tagOrder = void 0; this._startDate = void 0; this._endDate = void 0; this._dateAtEnd = void 0; this._cue = void 0; this._badValueForSameId = void 0; this.tagAnchor = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagAnchor) || null; this.tagOrder = (_dateRangeWithSameId$ = dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagOrder) != null ? _dateRangeWithSameId$ : tagCount; if (dateRangeWithSameId) { const previousAttr = dateRangeWithSameId.attr; for (const key in previousAttr) if (Object.prototype.hasOwnProperty.call(dateRangeAttr, key) && dateRangeAttr[key] !== previousAttr[key]) { logger.warn(`DATERANGE tag attribute: "${key}" does not match for tags with ID: "${dateRangeAttr.ID}"`); this._badValueForSameId = key; break; } dateRangeAttr = _extends(new AttrList({}), previousAttr, dateRangeAttr); } this.attr = dateRangeAttr; if (dateRangeWithSameId) { this._startDate = dateRangeWithSameId._startDate; this._cue = dateRangeWithSameId._cue; this._endDate = dateRangeWithSameId._endDate; this._dateAtEnd = dateRangeWithSameId._dateAtEnd; } else this._startDate = new Date(dateRangeAttr["START-DATE"]); if ("END-DATE" in this.attr) { const endDate = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.endDate) || new Date(this.attr["END-DATE"]); if (isFiniteNumber(endDate.getTime())) this._endDate = endDate; } } get id() { return this.attr.ID; } get class() { return this.attr.CLASS; } get cue() { const _cue = this._cue; if (_cue === void 0) return this._cue = this.attr.enumeratedStringList(this.attr.CUE ? "CUE" : "X-CUE", { pre: false, post: false, once: false }); return _cue; } get startTime() { const { tagAnchor } = this; if (tagAnchor === null || tagAnchor.programDateTime === null) { logger.warn(`Expected tagAnchor Fragment with PDT set for DateRange "${this.id}": ${tagAnchor}`); return NaN; } return tagAnchor.start + (this.startDate.getTime() - tagAnchor.programDateTime) / 1e3; } get startDate() { return this._startDate; } get endDate() { const dateAtEnd = this._endDate || this._dateAtEnd; if (dateAtEnd) return dateAtEnd; const duration = this.duration; if (duration !== null) return this._dateAtEnd = new Date(this._startDate.getTime() + duration * 1e3); return null; } get duration() { if ("DURATION" in this.attr) { const duration = this.attr.decimalFloatingPoint("DURATION"); if (isFiniteNumber(duration)) return duration; } else if (this._endDate) return (this._endDate.getTime() - this._startDate.getTime()) / 1e3; return null; } get plannedDuration() { if ("PLANNED-DURATION" in this.attr) return this.attr.decimalFloatingPoint("PLANNED-DURATION"); return null; } get endOnNext() { return this.attr.bool("END-ON-NEXT"); } get isInterstitial() { return this.class === CLASS_INTERSTITIAL; } get isValid() { return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class) && (!this.attr.CUE || !this.cue.pre && !this.cue.post || this.cue.pre !== this.cue.post) && (!this.isInterstitial || "X-ASSET-URI" in this.attr || "X-ASSET-LIST" in this.attr); } }; var DEFAULT_TARGET_DURATION = 10; /** * Object representing parsed data from an HLS Media Playlist. Found in {@link hls.js#Level.details}. */ var LevelDetails = class { constructor(baseUrl) { this.PTSKnown = false; this.alignedSliding = false; this.averagetargetduration = void 0; this.endCC = 0; this.endSN = 0; this.fragments = void 0; this.fragmentHint = void 0; this.partList = null; this.dateRanges = void 0; this.dateRangeTagCount = 0; this.live = true; this.requestScheduled = -1; this.ageHeader = 0; this.advancedDateTime = void 0; this.updated = true; this.advanced = true; this.misses = 0; this.startCC = 0; this.startSN = 0; this.startTimeOffset = null; this.targetduration = 0; this.totalduration = 0; this.type = null; this.url = void 0; this.m3u8 = ""; this.version = null; this.canBlockReload = false; this.canSkipUntil = 0; this.canSkipDateRanges = false; this.skippedSegments = 0; this.recentlyRemovedDateranges = void 0; this.partHoldBack = 0; this.holdBack = 0; this.partTarget = 0; this.preloadHint = void 0; this.renditionReports = void 0; this.tuneInGoal = 0; this.deltaUpdateFailed = void 0; this.driftStartTime = 0; this.driftEndTime = 0; this.driftStart = 0; this.driftEnd = 0; this.encryptedFragments = void 0; this.playlistParsingError = null; this.variableList = null; this.hasVariableRefs = false; this.appliedTimelineOffset = void 0; this.fragments = []; this.encryptedFragments = []; this.dateRanges = {}; this.url = baseUrl; } reloaded(previous) { if (!previous) { this.advanced = true; this.updated = true; return; } const partSnDiff = this.lastPartSn - previous.lastPartSn; const partIndexDiff = this.lastPartIndex - previous.lastPartIndex; this.updated = this.endSN !== previous.endSN || !!partIndexDiff || !!partSnDiff || !this.live; this.advanced = this.endSN > previous.endSN || partSnDiff > 0 || partSnDiff === 0 && partIndexDiff > 0; if (this.updated || this.advanced) this.misses = Math.floor(previous.misses * .6); else this.misses = previous.misses + 1; } hasKey(levelKey) { return this.encryptedFragments.some((frag) => { let decryptdata = frag.decryptdata; if (!decryptdata) { frag.setKeyFormat(levelKey.keyFormat); decryptdata = frag.decryptdata; } return !!decryptdata && levelKey.matches(decryptdata); }); } get hasProgramDateTime() { if (this.fragments.length) return isFiniteNumber(this.fragments[this.fragments.length - 1].programDateTime); return false; } get levelTargetDuration() { return this.averagetargetduration || this.targetduration || DEFAULT_TARGET_DURATION; } get drift() { const runTime = this.driftEndTime - this.driftStartTime; if (runTime > 0) return (this.driftEnd - this.driftStart) * 1e3 / runTime; return 1; } get edge() { return this.partEnd || this.fragmentEnd; } get partEnd() { var _this$partList; if ((_this$partList = this.partList) != null && _this$partList.length) return this.partList[this.partList.length - 1].end; return this.fragmentEnd; } get fragmentEnd() { if (this.fragments.length) return this.fragments[this.fragments.length - 1].end; return 0; } get fragmentStart() { if (this.fragments.length) return this.fragments[0].start; return 0; } get age() { if (this.advancedDateTime) return Math.max(Date.now() - this.advancedDateTime, 0) / 1e3; return 0; } get lastPartIndex() { var _this$partList2; if ((_this$partList2 = this.partList) != null && _this$partList2.length) return this.partList[this.partList.length - 1].index; return -1; } get maxPartIndex() { const partList = this.partList; if (partList) { const lastIndex = this.lastPartIndex; if (lastIndex !== -1) { for (let i = partList.length; i--;) if (partList[i].index > lastIndex) return partList[i].index; return lastIndex; } } return 0; } get lastPartSn() { var _this$partList3; if ((_this$partList3 = this.partList) != null && _this$partList3.length) return this.partList[this.partList.length - 1].fragment.sn; return this.endSN; } get expired() { if (this.live && this.age && this.misses < 3) { const playlistWindowDuration = this.partEnd - this.fragmentStart; return this.age > Math.max(playlistWindowDuration, this.totalduration) + this.levelTargetDuration; } return false; } }; function arrayValuesMatch(a, b) { if (a.length === b.length) return !a.some((value, i) => value !== b[i]); return false; } function optionalArrayValuesMatch(a, b) { if (!a && !b) return true; if (!a || !b) return false; return arrayValuesMatch(a, b); } function isFullSegmentEncryption(method) { return method === "AES-128" || method === "AES-256" || method === "AES-256-CTR"; } function getAesModeFromFullSegmentMethod(method) { switch (method) { case "AES-128": case "AES-256": return DecrypterAesMode.cbc; case "AES-256-CTR": return DecrypterAesMode.ctr; default: throw new Error(`invalid full segment method ${method}`); } } function base64Decode(base64encodedStr) { return Uint8Array.from(atob(base64encodedStr), (c) => c.charCodeAt(0)); } function strToUtf8array(str) { return Uint8Array.from(unescape(encodeURIComponent(str)), (c) => c.charCodeAt(0)); } function getKeyIdBytes(str) { const keyIdbytes = strToUtf8array(str).subarray(0, 16); const paddedkeyIdbytes = new Uint8Array(16); paddedkeyIdbytes.set(keyIdbytes, 16 - keyIdbytes.length); return paddedkeyIdbytes; } function changeEndianness(keyId) { const swap = function swap(array, from, to) { const cur = array[from]; array[from] = array[to]; array[to] = cur; }; swap(keyId, 0, 3); swap(keyId, 1, 2); swap(keyId, 4, 5); swap(keyId, 6, 7); } function convertDataUriToArrayBytes(uri) { const colonsplit = uri.split(":"); let keydata = null; if (colonsplit[0] === "data" && colonsplit.length === 2) { const semicolonsplit = colonsplit[1].split(";"); const commasplit = semicolonsplit[semicolonsplit.length - 1].split(","); if (commasplit.length === 2) { const isbase64 = commasplit[0] === "base64"; const data = commasplit[1]; if (isbase64) { semicolonsplit.splice(-1, 1); keydata = base64Decode(data); } else keydata = getKeyIdBytes(data); } } return keydata; } /** returns `undefined` is `self` is missing, e.g. in node */ var optionalSelf = typeof self !== "undefined" ? self : void 0; /** * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/requestMediaKeySystemAccess */ var KeySystems = { CLEARKEY: "org.w3.clearkey", FAIRPLAY: "com.apple.fps", PLAYREADY: "com.microsoft.playready", WIDEVINE: "com.widevine.alpha" }; var KeySystemFormats = { CLEARKEY: "org.w3.clearkey", FAIRPLAY: "com.apple.streamingkeydelivery", PLAYREADY: "com.microsoft.playready", WIDEVINE: "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" }; function keySystemFormatToKeySystemDomain(format) { switch (format) { case KeySystemFormats.FAIRPLAY: return KeySystems.FAIRPLAY; case KeySystemFormats.PLAYREADY: return KeySystems.PLAYREADY; case KeySystemFormats.WIDEVINE: return KeySystems.WIDEVINE; case KeySystemFormats.CLEARKEY: return KeySystems.CLEARKEY; } } function keySystemDomainToKeySystemFormat(keySystem) { switch (keySystem) { case KeySystems.FAIRPLAY: return KeySystemFormats.FAIRPLAY; case KeySystems.PLAYREADY: return KeySystemFormats.PLAYREADY; case KeySystems.WIDEVINE: return KeySystemFormats.WIDEVINE; case KeySystems.CLEARKEY: return KeySystemFormats.CLEARKEY; } } function getKeySystemsForConfig(config) { const { drmSystems, widevineLicenseUrl } = config; const keySystemsToAttempt = drmSystems ? [ KeySystems.FAIRPLAY, KeySystems.WIDEVINE, KeySystems.PLAYREADY, KeySystems.CLEARKEY ].filter((keySystem) => !!drmSystems[keySystem]) : []; if (!keySystemsToAttempt[KeySystems.WIDEVINE] && widevineLicenseUrl) keySystemsToAttempt.push(KeySystems.WIDEVINE); return keySystemsToAttempt; } var requestMediaKeySystemAccess = function(_optionalSelf$navigat) { if (optionalSelf != null && (_optionalSelf$navigat = optionalSelf.navigator) != null && _optionalSelf$navigat.requestMediaKeySystemAccess) return self.navigator.requestMediaKeySystemAccess.bind(self.navigator); else return null; }(); /** * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaKeySystemConfiguration */ function getSupportedMediaKeySystemConfigurations(keySystem, audioCodecs, videoCodecs, drmSystemOptions) { let initDataTypes; switch (keySystem) { case KeySystems.FAIRPLAY: initDataTypes = ["cenc", "sinf"]; break; case KeySystems.WIDEVINE: case KeySystems.PLAYREADY: initDataTypes = ["cenc"]; break; case KeySystems.CLEARKEY: initDataTypes = ["cenc", "keyids"]; break; default: throw new Error(`Unknown key-system: ${keySystem}`); } return createMediaKeySystemConfigurations(initDataTypes, audioCodecs, videoCodecs, drmSystemOptions); } function createMediaKeySystemConfigurations(initDataTypes, audioCodecs, videoCodecs, drmSystemOptions) { return [{ initDataTypes, persistentState: drmSystemOptions.persistentState || "optional", distinctiveIdentifier: drmSystemOptions.distinctiveIdentifier || "optional", sessionTypes: drmSystemOptions.sessionTypes || [drmSystemOptions.sessionType || "temporary"], audioCapabilities: audioCodecs.map((codec) => ({ contentType: `audio/mp4; codecs=${codec}`, robustness: drmSystemOptions.audioRobustness || "", encryptionScheme: drmSystemOptions.audioEncryptionScheme || null })), videoCapabilities: videoCodecs.map((codec) => ({ contentType: `video/mp4; codecs=${codec}`, robustness: drmSystemOptions.videoRobustness || "", encryptionScheme: drmSystemOptions.videoEncryptionScheme || null })) }]; } function isPersistentSessionType(drmSystemOptions) { var _drmSystemOptions$ses; return !!drmSystemOptions && (drmSystemOptions.sessionType === "persistent-license" || !!((_drmSystemOptions$ses = drmSystemOptions.sessionTypes) != null && _drmSystemOptions$ses.some((type) => type === "persistent-license"))); } function parsePlayReadyWRM(keyBytes) { const keyBytesUtf16 = new Uint16Array(keyBytes.buffer, keyBytes.byteOffset, keyBytes.byteLength / 2); const keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16)); const xmlKeyBytes = keyByteStr.substring(keyByteStr.indexOf("<"), keyByteStr.length); const keyData = new DOMParser().parseFromString(xmlKeyBytes, "text/xml").getElementsByTagName("KID")[0]; if (keyData) { const keyId = keyData.childNodes[0] ? keyData.childNodes[0].nodeValue : keyData.getAttribute("VALUE"); if (keyId) { const keyIdArray = base64Decode(keyId).subarray(0, 16); changeEndianness(keyIdArray); return keyIdArray; } } return null; } var keyUriToKeyIdMap = {}; var LevelKey = class LevelKey { static clearKeyUriToKeyIdMap() { keyUriToKeyIdMap = {}; } static setKeyIdForUri(uri, keyId) { keyUriToKeyIdMap[uri] = keyId; } static addKeyIdForUri(uri) { const val = Object.keys(keyUriToKeyIdMap).length % Number.MAX_SAFE_INTEGER; const keyId = new Uint8Array(16); new DataView(keyId.buffer, 12, 4).setUint32(0, val); keyUriToKeyIdMap[uri] = keyId; return keyId; } constructor(method, uri, format, formatversions = [1], iv = null, keyId) { this.uri = void 0; this.method = void 0; this.keyFormat = void 0; this.keyFormatVersions = void 0; this.encrypted = void 0; this.isCommonEncryption = void 0; this.iv = null; this.key = null; this.keyId = null; this.pssh = null; this.method = method; this.uri = uri; this.keyFormat = format; this.keyFormatVersions = formatversions; this.iv = iv; this.encrypted = method ? method !== "NONE" : false; this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method); if (keyId != null && keyId.startsWith("0x")) this.keyId = new Uint8Array(hexToArrayBuffer(keyId)); } matches(key) { return key.uri === this.uri && key.method === this.method && key.encrypted === this.encrypted && key.keyFormat === this.keyFormat && arrayValuesMatch(key.keyFormatVersions, this.keyFormatVersions) && optionalArrayValuesMatch(key.iv, this.iv) && optionalArrayValuesMatch(key.keyId, this.keyId); } isSupported() { if (this.method) { if (isFullSegmentEncryption(this.method) || this.method === "NONE") return true; if (this.keyFormat === "identity") return this.method === "SAMPLE-AES"; else switch (this.keyFormat) { case KeySystemFormats.FAIRPLAY: case KeySystemFormats.WIDEVINE: case KeySystemFormats.PLAYREADY: case KeySystemFormats.CLEARKEY: return [ "SAMPLE-AES", "SAMPLE-AES-CENC", "SAMPLE-AES-CTR" ].indexOf(this.method) !== -1; } } return false; } getDecryptData(sn, levelKeys) { if (!this.encrypted || !this.uri) return null; if (isFullSegmentEncryption(this.method)) { let iv = this.iv; if (!iv) { if (typeof sn !== "number") { logger.warn(`missing IV for initialization segment with method="${this.method}" - compliance issue`); sn = 0; } iv = createInitializationVector(sn); } return new LevelKey(this.method, this.uri, "identity", this.keyFormatVersions, iv); } if (this.keyId) { const assignedKeyId = keyUriToKeyIdMap[this.uri]; if (assignedKeyId && !arrayValuesMatch(this.keyId, assignedKeyId)) LevelKey.setKeyIdForUri(this.uri, this.keyId); if (this.pssh) return this; } const keyBytes = convertDataUriToArrayBytes(this.uri); if (keyBytes) switch (this.keyFormat) { case KeySystemFormats.WIDEVINE: this.pssh = keyBytes; if (!this.keyId) { const results = parseMultiPssh(keyBytes.buffer); if (results.length) { var _psshData$kids; const psshData = results[0]; this.keyId = (_psshData$kids = psshData.kids) != null && _psshData$kids.length ? psshData.kids[0] : null; } } if (!this.keyId) this.keyId = getKeyIdFromPlayReadyKey(levelKeys); break; case KeySystemFormats.PLAYREADY: { const PlayReadyKeySystemUUID = new Uint8Array([ 154, 4, 240, 121, 152, 64, 66, 134, 171, 146, 230, 91, 224, 136, 95, 149 ]); this.pssh = mp4pssh(PlayReadyKeySystemUUID, null, keyBytes); this.keyId = parsePlayReadyWRM(keyBytes); break; } default: { let keydata = keyBytes.subarray(0, 16); if (keydata.length !== 16) { const padded = new Uint8Array(16); padded.set(keydata, 16 - keydata.length); keydata = padded; } this.keyId = keydata; break; } } if (!this.keyId || this.keyId.byteLength !== 16) { let keyId; keyId = getKeyIdFromWidevineKey(levelKeys); if (!keyId) { keyId = getKeyIdFromPlayReadyKey(levelKeys); if (!keyId) keyId = keyUriToKeyIdMap[this.uri]; } if (keyId) { this.keyId = keyId; LevelKey.setKeyIdForUri(this.uri, keyId); } } return this; } }; function getKeyIdFromWidevineKey(levelKeys) { const widevineKey = levelKeys == null ? void 0 : levelKeys[KeySystemFormats.WIDEVINE]; if (widevineKey) return widevineKey.keyId; return null; } function getKeyIdFromPlayReadyKey(levelKeys) { const playReadyKey = levelKeys == null ? void 0 : levelKeys[KeySystemFormats.PLAYREADY]; if (playReadyKey) { const playReadyKeyBytes = convertDataUriToArrayBytes(playReadyKey.uri); if (playReadyKeyBytes) return parsePlayReadyWRM(playReadyKeyBytes); } return null; } function createInitializationVector(segmentNumber) { const uint8View = new Uint8Array(16); for (let i = 12; i < 16; i++) uint8View[i] = segmentNumber >> 8 * (15 - i) & 255; return uint8View; } var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g; var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g; var IS_MEDIA_PLAYLIST = /^#EXT(?:INF|-X-TARGETDURATION):/m; var LEVEL_PLAYLIST_REGEX_FAST = new RegExp([ /#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source, /(?!#) *(\S[^\r\n]*)/.source, /#.*/.source ].join("|"), "g"); var LEVEL_PLAYLIST_REGEX_SLOW = new RegExp([ /#EXT-X-(PROGRAM-DATE-TIME|BYTERANGE|DATERANGE|DEFINE|KEY|MAP|PART|PART-INF|PLAYLIST-TYPE|PRELOAD-HINT|RENDITION-REPORT|SERVER-CONTROL|SKIP|START):(.+)/.source, /#EXT-X-(BITRATE|DISCONTINUITY-SEQUENCE|MEDIA-SEQUENCE|TARGETDURATION|VERSION): *(\d+)/.source, /#EXT-X-(DISCONTINUITY|ENDLIST|GAP|INDEPENDENT-SEGMENTS)/.source, /(#)([^:]*):(.*)/.source, /(#)(.*)(?:.*)\r?\n?/.source ].join("|")); var M3U8Parser = class M3U8Parser { static findGroup(groups, mediaGroupId) { for (let i = 0; i < groups.length; i++) { const group = groups[i]; if (group.id === mediaGroupId) return group; } } static resolve(url, baseUrl) { return urlToolkitExports.buildAbsoluteURL(baseUrl, url, { alwaysNormalize: true }); } static isMediaPlaylist(str) { return IS_MEDIA_PLAYLIST.test(str); } static parseMasterPlaylist(string, baseurl) { const parsed = { contentSteering: null, levels: [], playlistParsingError: null, sessionData: null, sessionKeys: null, startTimeOffset: null, variableList: null, hasVariableRefs: hasVariableReferences(string) }; const levelsWithKnownCodecs = []; MASTER_PLAYLIST_REGEX.lastIndex = 0; if (!string.startsWith("#EXTM3U")) { parsed.playlistParsingError = /* @__PURE__ */ new Error("no EXTM3U delimiter"); return parsed; } let result; while ((result = MASTER_PLAYLIST_REGEX.exec(string)) != null) if (result[1]) { var _level$unknownCodecs; const attrs = new AttrList(result[1], parsed); const uri = substituteVariables(parsed, result[2]); const level = { attrs, bitrate: attrs.decimalInteger("BANDWIDTH") || attrs.decimalInteger("AVERAGE-BANDWIDTH"), name: attrs.NAME, url: M3U8Parser.resolve(uri, baseurl) }; const resolution = attrs.decimalResolution("RESOLUTION"); if (resolution) { level.width = resolution.width; level.height = resolution.height; } setCodecs(attrs.CODECS, level); const supplementalCodecs = attrs["SUPPLEMENTAL-CODECS"]; if (supplementalCodecs) { level.supplemental = {}; setCodecs(supplementalCodecs, level.supplemental); } if (!((_level$unknownCodecs = level.unknownCodecs) != null && _level$unknownCodecs.length)) levelsWithKnownCodecs.push(level); parsed.levels.push(level); } else if (result[3]) { const tag = result[3]; const attributes = result[4]; switch (tag) { case "SESSION-DATA": { const sessionAttrs = new AttrList(attributes, parsed); const dataId = sessionAttrs["DATA-ID"]; if (dataId) { if (parsed.sessionData === null) parsed.sessionData = {}; parsed.sessionData[dataId] = sessionAttrs; } break; } case "SESSION-KEY": { const sessionKey = parseKey(attributes, baseurl, parsed); if (sessionKey.encrypted && sessionKey.isSupported()) { if (parsed.sessionKeys === null) parsed.sessionKeys = []; parsed.sessionKeys.push(sessionKey); } else logger.warn(`[Keys] Ignoring invalid EXT-X-SESSION-KEY tag: "${attributes}"`); break; } case "DEFINE": addVariableDefinition(parsed, new AttrList(attributes, parsed), baseurl); break; case "CONTENT-STEERING": { const contentSteeringAttributes = new AttrList(attributes, parsed); parsed.contentSteering = { uri: M3U8Parser.resolve(contentSteeringAttributes["SERVER-URI"], baseurl), pathwayId: contentSteeringAttributes["PATHWAY-ID"] || "." }; break; } case "START": parsed.startTimeOffset = parseStartTimeOffset(attributes); break; } } parsed.levels = levelsWithKnownCodecs.length > 0 && levelsWithKnownCodecs.length < parsed.levels.length ? levelsWithKnownCodecs : parsed.levels; if (parsed.levels.length === 0) parsed.playlistParsingError = /* @__PURE__ */ new Error("no levels found in manifest"); return parsed; } static parseMasterPlaylistMedia(string, baseurl, parsed) { let result; const results = {}; const levels = parsed.levels; const groupsByType = { AUDIO: levels.map((level) => ({ id: level.attrs.AUDIO, audioCodec: level.audioCodec })), SUBTITLES: levels.map((level) => ({ id: level.attrs.SUBTITLES, textCodec: level.textCodec })), "CLOSED-CAPTIONS": [] }; let id = 0; MASTER_PLAYLIST_MEDIA_REGEX.lastIndex = 0; while ((result = MASTER_PLAYLIST_MEDIA_REGEX.exec(string)) !== null) { const attrs = new AttrList(result[1], parsed); const type = attrs.TYPE; if (type) { const groups = groupsByType[type]; const medias = results[type] || []; results[type] = medias; const lang = attrs.LANGUAGE; const assocLang = attrs["ASSOC-LANGUAGE"]; const channels = attrs.CHANNELS; const characteristics = attrs.CHARACTERISTICS; const instreamId = attrs["INSTREAM-ID"]; const media = { attrs, bitrate: 0, id: id++, groupId: attrs["GROUP-ID"] || "", name: attrs.NAME || lang || "", type, default: attrs.bool("DEFAULT"), autoselect: attrs.bool("AUTOSELECT"), forced: attrs.bool("FORCED"), lang, url: attrs.URI ? M3U8Parser.resolve(attrs.URI, baseurl) : "" }; if (assocLang) media.assocLang = assocLang; if (channels) media.channels = channels; if (characteristics) media.characteristics = characteristics; if (instreamId) media.instreamId = instreamId; if (groups != null && groups.length) { const groupCodec = M3U8Parser.findGroup(groups, media.groupId) || groups[0]; assignCodec(media, groupCodec, "audioCodec"); assignCodec(media, groupCodec, "textCodec"); } medias.push(media); } } return results; } static parseLevelPlaylist(string, baseurl, id, type, levelUrlId, multivariantVariableList) { var _LEVEL_PLAYLIST_REGEX; const base = { url: baseurl }; const level = new LevelDetails(baseurl); const fragments = level.fragments; const programDateTimes = []; let currentInitSegment = null; let currentSN = 0; let currentPart = 0; let totalduration = 0; let discontinuityCounter = 0; let currentBitrate = 0; let prevFrag = null; let frag = new Fragment(type, base); let result; let i; let levelkeys; let firstPdtIndex = -1; let createNextFrag = false; let nextByteRange = null; let serverControlAttrs; LEVEL_PLAYLIST_REGEX_FAST.lastIndex = 0; level.m3u8 = string; level.hasVariableRefs = hasVariableReferences(string); if (((_LEVEL_PLAYLIST_REGEX = LEVEL_PLAYLIST_REGEX_FAST.exec(string)) == null ? void 0 : _LEVEL_PLAYLIST_REGEX[0]) !== "#EXTM3U") { level.playlistParsingError = /* @__PURE__ */ new Error("Missing format identifier #EXTM3U"); return level; } while ((result = LEVEL_PLAYLIST_REGEX_FAST.exec(string)) !== null) { if (createNextFrag) { createNextFrag = false; frag = new Fragment(type, base); frag.playlistOffset = totalduration; frag.setStart(totalduration); frag.sn = currentSN; frag.cc = discontinuityCounter; if (currentBitrate) frag.bitrate = currentBitrate; frag.level = id; if (currentInitSegment) { frag.initSegment = currentInitSegment; if (currentInitSegment.rawProgramDateTime) { frag.rawProgramDateTime = currentInitSegment.rawProgramDateTime; currentInitSegment.rawProgramDateTime = null; } if (nextByteRange) { frag.setByteRange(nextByteRange); nextByteRange = null; } } } const duration = result[1]; if (duration) { frag.duration = parseFloat(duration); const title = (" " + result[2]).slice(1); frag.title = title || null; frag.tagList.push(title ? [ "INF", duration, title ] : ["INF", duration]); } else if (result[3]) { if (isFiniteNumber(frag.duration)) { frag.playlistOffset = totalduration; frag.setStart(totalduration); if (levelkeys) setFragLevelKeys(frag, levelkeys, level); frag.sn = currentSN; frag.level = id; frag.cc = discontinuityCounter; fragments.push(frag); const uri = (" " + result[3]).slice(1); frag.relurl = substituteVariables(level, uri); assignProgramDateTime(frag, prevFrag, programDateTimes); prevFrag = frag; totalduration += frag.duration; currentSN++; currentPart = 0; createNextFrag = true; } } else { result = result[0].match(LEVEL_PLAYLIST_REGEX_SLOW); if (!result) { logger.warn("No matches on slow regex match for level playlist!"); continue; } for (i = 1; i < result.length; i++) if (result[i] !== void 0) break; const tag = (" " + result[i]).slice(1); const value1 = (" " + result[i + 1]).slice(1); const value2 = result[i + 2] ? (" " + result[i + 2]).slice(1) : null; switch (tag) { case "BYTERANGE": if (prevFrag) frag.setByteRange(value1, prevFrag); else frag.setByteRange(value1); break; case "PROGRAM-DATE-TIME": frag.rawProgramDateTime = value1; frag.tagList.push(["PROGRAM-DATE-TIME", value1]); if (firstPdtIndex === -1) firstPdtIndex = fragments.length; break; case "PLAYLIST-TYPE": if (level.type) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); level.type = value1.toUpperCase(); break; case "MEDIA-SEQUENCE": if (level.startSN !== 0) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); else if (fragments.length > 0) assignMustAppearBeforeSegmentsError(level, tag, result); currentSN = level.startSN = parseInt(value1); break; case "SKIP": { if (level.skippedSegments) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); const skipAttrs = new AttrList(value1, level); const skippedSegments = skipAttrs.decimalInteger("SKIPPED-SEGMENTS"); if (isFiniteNumber(skippedSegments)) { level.skippedSegments += skippedSegments; for (let _i = skippedSegments; _i--;) fragments.push(null); currentSN += skippedSegments; } const recentlyRemovedDateranges = skipAttrs.enumeratedString("RECENTLY-REMOVED-DATERANGES"); if (recentlyRemovedDateranges) level.recentlyRemovedDateranges = (level.recentlyRemovedDateranges || []).concat(recentlyRemovedDateranges.split(" ")); break; } case "TARGETDURATION": if (level.targetduration !== 0) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); level.targetduration = Math.max(parseInt(value1), 1); break; case "VERSION": if (level.version !== null) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); level.version = parseInt(value1); break; case "INDEPENDENT-SEGMENTS": break; case "ENDLIST": if (!level.live) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); level.live = false; break; case "#": if (value1 || value2) frag.tagList.push(value2 ? [value1, value2] : [value1]); break; case "DISCONTINUITY": discontinuityCounter++; frag.tagList.push(["DIS"]); break; case "GAP": frag.gap = true; frag.tagList.push([tag]); break; case "BITRATE": frag.tagList.push([tag, value1]); currentBitrate = parseInt(value1) * 1e3; if (isFiniteNumber(currentBitrate)) frag.bitrate = currentBitrate; else currentBitrate = 0; break; case "DATERANGE": { const dateRangeAttr = new AttrList(value1, level); const dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID], level.dateRangeTagCount); level.dateRangeTagCount++; if (dateRange.isValid || level.skippedSegments) level.dateRanges[dateRange.id] = dateRange; else logger.warn(`Ignoring invalid DATERANGE tag: "${value1}"`); frag.tagList.push(["EXT-X-DATERANGE", value1]); break; } case "DEFINE": { const variableAttributes = new AttrList(value1, level); if ("IMPORT" in variableAttributes) importVariableDefinition(level, variableAttributes, multivariantVariableList); else addVariableDefinition(level, variableAttributes, baseurl); } break; case "DISCONTINUITY-SEQUENCE": if (level.startCC !== 0) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); else if (fragments.length > 0) assignMustAppearBeforeSegmentsError(level, tag, result); level.startCC = discontinuityCounter = parseInt(value1); break; case "KEY": { const levelKey = parseKey(value1, baseurl, level); if (levelKey.isSupported()) { if (levelKey.method === "NONE") { levelkeys = void 0; break; } if (!levelkeys) levelkeys = {}; const currentKey = levelkeys[levelKey.keyFormat]; if (!(currentKey != null && currentKey.matches(levelKey))) { if (currentKey) levelkeys = _extends({}, levelkeys); levelkeys[levelKey.keyFormat] = levelKey; } } else logger.warn(`[Keys] Ignoring unsupported EXT-X-KEY tag: "${value1}"`); break; } case "START": level.startTimeOffset = parseStartTimeOffset(value1); break; case "MAP": { const mapAttrs = new AttrList(value1, level); if (frag.duration) { const init = new Fragment(type, base); setInitSegment(init, mapAttrs, id, levelkeys); currentInitSegment = init; frag.initSegment = currentInitSegment; if (currentInitSegment.rawProgramDateTime && !frag.rawProgramDateTime) frag.rawProgramDateTime = currentInitSegment.rawProgramDateTime; } else { const end = frag.byteRangeEndOffset; if (end) { const start = frag.byteRangeStartOffset; nextByteRange = `${end - start}@${start}`; } else nextByteRange = null; setInitSegment(frag, mapAttrs, id, levelkeys); currentInitSegment = frag; createNextFrag = true; } currentInitSegment.cc = discontinuityCounter; break; } case "SERVER-CONTROL": if (serverControlAttrs) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); serverControlAttrs = new AttrList(value1); level.canBlockReload = serverControlAttrs.bool("CAN-BLOCK-RELOAD"); level.canSkipUntil = serverControlAttrs.optionalFloat("CAN-SKIP-UNTIL", 0); level.canSkipDateRanges = level.canSkipUntil > 0 && serverControlAttrs.bool("CAN-SKIP-DATERANGES"); level.partHoldBack = serverControlAttrs.optionalFloat("PART-HOLD-BACK", 0); level.holdBack = serverControlAttrs.optionalFloat("HOLD-BACK", 0); break; case "PART-INF": if (level.partTarget) assignMultipleMediaPlaylistTagOccuranceError(level, tag, result); level.partTarget = new AttrList(value1).decimalFloatingPoint("PART-TARGET"); break; case "PART": { let partList = level.partList; if (!partList) partList = level.partList = []; const previousFragmentPart = currentPart > 0 ? partList[partList.length - 1] : void 0; const index = currentPart++; const part = new Part(new AttrList(value1, level), frag, base, index, previousFragmentPart); partList.push(part); frag.duration += part.duration; break; } case "PRELOAD-HINT": level.preloadHint = new AttrList(value1, level); break; case "RENDITION-REPORT": { const renditionReportAttrs = new AttrList(value1, level); level.renditionReports = level.renditionReports || []; level.renditionReports.push(renditionReportAttrs); break; } default: logger.warn(`line parsed but not handled: ${result}`); break; } } } if (prevFrag && !prevFrag.relurl) { fragments.pop(); totalduration -= prevFrag.duration; if (level.partList) level.fragmentHint = prevFrag; } else if (level.partList) { assignProgramDateTime(frag, prevFrag, programDateTimes); frag.cc = discontinuityCounter; level.fragmentHint = frag; if (levelkeys) setFragLevelKeys(frag, levelkeys, level); } if (!level.targetduration) level.playlistParsingError = /* @__PURE__ */ new Error(`Missing Target Duration`); const fragmentLength = fragments.length; const firstFragment = fragments[0]; const lastFragment = fragments[fragmentLength - 1]; totalduration += level.skippedSegments * level.targetduration; if (totalduration > 0 && fragmentLength && lastFragment) { level.averagetargetduration = totalduration / fragmentLength; const lastSn = lastFragment.sn; level.endSN = lastSn !== "initSegment" ? lastSn : 0; if (!level.live) lastFragment.endList = true; /** * Backfill any missing PDT values * "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after * one or more Media Segment URIs, the client SHOULD extrapolate * backward from that tag (using EXTINF durations and/or media * timestamps) to associate dates with those segments." * We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs * computed. */ if (firstPdtIndex > 0) { backfillProgramDateTimes(fragments, firstPdtIndex); if (firstFragment) programDateTimes.unshift(firstFragment); } } if (level.fragmentHint) totalduration += level.fragmentHint.duration; level.totalduration = totalduration; if (programDateTimes.length && level.dateRangeTagCount && firstFragment) mapDateRanges(programDateTimes, level); level.endCC = discontinuityCounter; return level; } }; function mapDateRanges(programDateTimes, details) { let programDateTimeCount = programDateTimes.length; if (!programDateTimeCount) if (details.hasProgramDateTime) { const lastFragment = details.fragments[details.fragments.length - 1]; programDateTimes.push(lastFragment); programDateTimeCount++; } else return; const lastProgramDateTime = programDateTimes[programDateTimeCount - 1]; const playlistEnd = details.live ? Infinity : details.totalduration; const dateRangeIds = Object.keys(details.dateRanges); for (let i = dateRangeIds.length; i--;) { const dateRange = details.dateRanges[dateRangeIds[i]]; const startDateTime = dateRange.startDate.getTime(); dateRange.tagAnchor = lastProgramDateTime.ref; for (let j = programDateTimeCount; j--;) { var _programDateTimes$j; if (((_programDateTimes$j = programDateTimes[j]) == null ? void 0 : _programDateTimes$j.sn) < details.startSN) break; const fragIndex = findFragmentWithStartDate(details, startDateTime, programDateTimes, j, playlistEnd); if (fragIndex !== -1) { dateRange.tagAnchor = details.fragments[fragIndex].ref; break; } } } } function findFragmentWithStartDate(details, startDateTime, programDateTimes, index, endTime) { const pdtFragment = programDateTimes[index]; if (pdtFragment) { const pdtStart = pdtFragment.programDateTime; if (startDateTime >= pdtStart || index === 0) { var _programDateTimes; if (startDateTime <= pdtStart + ((((_programDateTimes = programDateTimes[index + 1]) == null ? void 0 : _programDateTimes.start) || endTime) - pdtFragment.start) * 1e3) { const startIndex = programDateTimes[index].sn - details.startSN; if (startIndex < 0) return -1; const fragments = details.fragments; if (fragments.length > programDateTimes.length) { const endIndex = (programDateTimes[index + 1] || fragments[fragments.length - 1]).sn - details.startSN; for (let i = endIndex; i > startIndex; i--) { const fragStartDateTime = fragments[i].programDateTime; if (startDateTime >= fragStartDateTime && startDateTime < fragStartDateTime + fragments[i].duration * 1e3) return i; } } return startIndex; } } } return -1; } function parseKey(keyTagAttributes, baseurl, parsed) { var _keyAttrs$METHOD, _keyAttrs$KEYFORMAT; const keyAttrs = new AttrList(keyTagAttributes, parsed); const decryptmethod = (_keyAttrs$METHOD = keyAttrs.METHOD) != null ? _keyAttrs$METHOD : ""; const decrypturi = keyAttrs.URI; const decryptiv = keyAttrs.hexadecimalInteger("IV"); const decryptkeyformatversions = keyAttrs.KEYFORMATVERSIONS; const decryptkeyformat = (_keyAttrs$KEYFORMAT = keyAttrs.KEYFORMAT) != null ? _keyAttrs$KEYFORMAT : "identity"; if (decrypturi && keyAttrs.IV && !decryptiv) logger.error(`Invalid IV: ${keyAttrs.IV}`); return new LevelKey(decryptmethod, decrypturi ? M3U8Parser.resolve(decrypturi, baseurl) : "", decryptkeyformat, (decryptkeyformatversions ? decryptkeyformatversions : "1").split("/").map(Number).filter(Number.isFinite), decryptiv, keyAttrs.KEYID); } function parseStartTimeOffset(startAttributes) { const startTimeOffset = new AttrList(startAttributes).decimalFloatingPoint("TIME-OFFSET"); if (isFiniteNumber(startTimeOffset)) return startTimeOffset; return null; } function setCodecs(codecsAttributeValue, level) { let codecs = (codecsAttributeValue || "").split(/[ ,]+/).filter((c) => c); [ "video", "audio", "text" ].forEach((type) => { const filtered = codecs.filter((codec) => isCodecType(codec, type)); if (filtered.length) { level[`${type}Codec`] = filtered.map((c) => c.split("/")[0]).join(","); codecs = codecs.filter((codec) => filtered.indexOf(codec) === -1); } }); level.unknownCodecs = codecs; } function assignCodec(media, groupItem, codecProperty) { const codecValue = groupItem[codecProperty]; if (codecValue) media[codecProperty] = codecValue; } function backfillProgramDateTimes(fragments, firstPdtIndex) { let fragPrev = fragments[firstPdtIndex]; for (let i = firstPdtIndex; i--;) { const frag = fragments[i]; if (!frag) return; frag.programDateTime = fragPrev.programDateTime - frag.duration * 1e3; fragPrev = frag; } } function assignProgramDateTime(frag, prevFrag, programDateTimes) { if (frag.rawProgramDateTime) programDateTimes.push(frag); else if (prevFrag != null && prevFrag.programDateTime) frag.programDateTime = prevFrag.endProgramDateTime; } function setInitSegment(frag, mapAttrs, id, levelkeys) { frag.relurl = mapAttrs.URI; if (mapAttrs.BYTERANGE) frag.setByteRange(mapAttrs.BYTERANGE); frag.level = id; frag.sn = "initSegment"; if (levelkeys) frag.levelkeys = levelkeys; frag.initSegment = null; } function setFragLevelKeys(frag, levelkeys, level) { frag.levelkeys = levelkeys; const { encryptedFragments } = level; if ((!encryptedFragments.length || encryptedFragments[encryptedFragments.length - 1].levelkeys !== levelkeys) && Object.keys(levelkeys).some((format) => levelkeys[format].isCommonEncryption)) encryptedFragments.push(frag); } function assignMultipleMediaPlaylistTagOccuranceError(level, tag, result) { level.playlistParsingError = /* @__PURE__ */ new Error(`#EXT-X-${tag} must not appear more than once (${result[0]})`); } function assignMustAppearBeforeSegmentsError(level, tag, result) { level.playlistParsingError = /* @__PURE__ */ new Error(`#EXT-X-${tag} must appear before the first Media Segment (${result[0]})`); } function updateFromToPTS(fragFrom, fragTo) { const fragToPTS = fragTo.startPTS; if (isFiniteNumber(fragToPTS)) { let duration = 0; let frag; if (fragTo.sn > fragFrom.sn) { duration = fragToPTS - fragFrom.start; frag = fragFrom; } else { duration = fragFrom.start - fragToPTS; frag = fragTo; } if (frag.duration !== duration) frag.setDuration(duration); } else if (fragTo.sn > fragFrom.sn) if (fragFrom.cc === fragTo.cc && fragFrom.minEndPTS) fragTo.setStart(fragFrom.start + (fragFrom.minEndPTS - fragFrom.start)); else fragTo.setStart(fragFrom.start + fragFrom.duration); else fragTo.setStart(Math.max(fragFrom.start - fragTo.duration, 0)); } function updateFragPTSDTS(details, frag, startPTS, endPTS, startDTS, endDTS, logger) { if (endPTS - startPTS <= 0) { logger.warn("Fragment should have a positive duration", frag); endPTS = startPTS + frag.duration; endDTS = startDTS + frag.duration; } let maxStartPTS = startPTS; let minEndPTS = endPTS; const fragStartPts = frag.startPTS; const fragEndPts = frag.endPTS; if (isFiniteNumber(fragStartPts)) { const deltaPTS = Math.abs(fragStartPts - startPTS); if (details && deltaPTS > details.totalduration) logger.warn(`media timestamps and playlist times differ by ${deltaPTS}s for level ${frag.level} ${details.url}`); else if (!isFiniteNumber(frag.deltaPTS)) frag.deltaPTS = deltaPTS; else frag.deltaPTS = Math.max(deltaPTS, frag.deltaPTS); maxStartPTS = Math.max(startPTS, fragStartPts); startPTS = Math.min(startPTS, fragStartPts); startDTS = frag.startDTS !== void 0 ? Math.min(startDTS, frag.startDTS) : startDTS; minEndPTS = Math.min(endPTS, fragEndPts); endPTS = Math.max(endPTS, fragEndPts); endDTS = frag.endDTS !== void 0 ? Math.max(endDTS, frag.endDTS) : endDTS; } const drift = startPTS - frag.start; if (frag.start !== 0) frag.setStart(startPTS); frag.setDuration(endPTS - frag.start); frag.startPTS = startPTS; frag.maxStartPTS = maxStartPTS; frag.startDTS = startDTS; frag.endPTS = endPTS; frag.minEndPTS = minEndPTS; frag.endDTS = endDTS; const sn = frag.sn; if (!details || sn < details.startSN || sn > details.endSN) return 0; let i; const fragIdx = sn - details.startSN; const fragments = details.fragments; fragments[fragIdx] = frag; for (i = fragIdx; i > 0; i--) updateFromToPTS(fragments[i], fragments[i - 1]); for (i = fragIdx; i < fragments.length - 1; i++) updateFromToPTS(fragments[i], fragments[i + 1]); if (details.fragmentHint) updateFromToPTS(fragments[fragments.length - 1], details.fragmentHint); details.PTSKnown = details.alignedSliding = true; return drift; } function mergeDetails(oldDetails, newDetails, logger) { if (oldDetails === newDetails) return; let currentInitSegment = null; const oldFragments = oldDetails.fragments; for (let i = oldFragments.length - 1; i >= 0; i--) { const oldInit = oldFragments[i].initSegment; if (oldInit) { currentInitSegment = oldInit; break; } } if (oldDetails.fragmentHint) delete oldDetails.fragmentHint.endPTS; let PTSFrag; mapFragmentIntersection(oldDetails, newDetails, (oldFrag, newFrag, newFragIndex, newFragments) => { if ((!newDetails.startCC || newDetails.skippedSegments) && newFrag.cc !== oldFrag.cc) { const ccOffset = oldFrag.cc - newFrag.cc; for (let i = newFragIndex; i < newFragments.length; i++) newFragments[i].cc += ccOffset; newDetails.endCC = newFragments[newFragments.length - 1].cc; } if (isFiniteNumber(oldFrag.startPTS) && isFiniteNumber(oldFrag.endPTS)) { newFrag.setStart(newFrag.startPTS = oldFrag.startPTS); newFrag.startDTS = oldFrag.startDTS; newFrag.maxStartPTS = oldFrag.maxStartPTS; newFrag.endPTS = oldFrag.endPTS; newFrag.endDTS = oldFrag.endDTS; newFrag.minEndPTS = oldFrag.minEndPTS; newFrag.setDuration(oldFrag.endPTS - oldFrag.startPTS); if (newFrag.duration) PTSFrag = newFrag; newDetails.PTSKnown = newDetails.alignedSliding = true; } if (oldFrag.hasStreams) newFrag.elementaryStreams = oldFrag.elementaryStreams; newFrag.loader = oldFrag.loader; if (oldFrag.hasStats) newFrag.stats = oldFrag.stats; if (oldFrag.initSegment) { newFrag.initSegment = oldFrag.initSegment; currentInitSegment = oldFrag.initSegment; } }); const newFragments = newDetails.fragments; const fragmentsToCheck = newDetails.fragmentHint ? newFragments.concat(newDetails.fragmentHint) : newFragments; if (currentInitSegment) fragmentsToCheck.forEach((frag) => { var _currentInitSegment; if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) frag.initSegment = currentInitSegment; }); if (newDetails.skippedSegments) { newDetails.deltaUpdateFailed = newFragments.some((frag) => !frag); if (newDetails.deltaUpdateFailed) { logger.warn("[level-helper] Previous playlist missing segments skipped in delta playlist"); for (let i = newDetails.skippedSegments; i--;) newFragments.shift(); newDetails.startSN = newFragments[0].sn; } else { if (newDetails.canSkipDateRanges) newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails, logger); const programDateTimes = oldDetails.fragments.filter((frag) => frag.rawProgramDateTime); if (oldDetails.hasProgramDateTime && !newDetails.hasProgramDateTime) { for (let i = 1; i < fragmentsToCheck.length; i++) if (fragmentsToCheck[i].programDateTime === null) assignProgramDateTime(fragmentsToCheck[i], fragmentsToCheck[i - 1], programDateTimes); } mapDateRanges(programDateTimes, newDetails); } newDetails.endCC = newFragments[newFragments.length - 1].cc; } if (!newDetails.startCC) { var _fragPriorToNewStart$; const fragPriorToNewStart = getFragmentWithSN(oldDetails, newDetails.startSN - 1); newDetails.startCC = (_fragPriorToNewStart$ = fragPriorToNewStart == null ? void 0 : fragPriorToNewStart.cc) != null ? _fragPriorToNewStart$ : newFragments[0].cc; } mapPartIntersection(oldDetails.partList, newDetails.partList, (oldPart, newPart) => { newPart.elementaryStreams = oldPart.elementaryStreams; newPart.stats = oldPart.stats; }); if (PTSFrag) updateFragPTSDTS(newDetails, PTSFrag, PTSFrag.startPTS, PTSFrag.endPTS, PTSFrag.startDTS, PTSFrag.endDTS, logger); else adjustSliding(oldDetails, newDetails); if (newFragments.length) newDetails.totalduration = newDetails.edge - newFragments[0].start; newDetails.driftStartTime = oldDetails.driftStartTime; newDetails.driftStart = oldDetails.driftStart; const advancedDateTime = newDetails.advancedDateTime; if (newDetails.advanced && advancedDateTime) { const edge = newDetails.edge; if (!newDetails.driftStart) { newDetails.driftStartTime = advancedDateTime; newDetails.driftStart = edge; } newDetails.driftEndTime = advancedDateTime; newDetails.driftEnd = edge; } else { newDetails.driftEndTime = oldDetails.driftEndTime; newDetails.driftEnd = oldDetails.driftEnd; newDetails.advancedDateTime = oldDetails.advancedDateTime; } if (newDetails.requestScheduled === -1) newDetails.requestScheduled = oldDetails.requestScheduled; } function mergeDateRanges(oldDateRanges, newDetails, logger) { const { dateRanges: deltaDateRanges, recentlyRemovedDateranges } = newDetails; const dateRanges = _extends({}, oldDateRanges); if (recentlyRemovedDateranges) recentlyRemovedDateranges.forEach((id) => { delete dateRanges[id]; }); const mergeCount = Object.keys(dateRanges).length; if (!mergeCount) return deltaDateRanges; Object.keys(deltaDateRanges).forEach((id) => { const mergedDateRange = dateRanges[id]; const dateRange = new DateRange(deltaDateRanges[id].attr, mergedDateRange); if (dateRange.isValid) { dateRanges[id] = dateRange; if (!mergedDateRange) dateRange.tagOrder += mergeCount; } else logger.warn(`Ignoring invalid Playlist Delta Update DATERANGE tag: "${stringify(deltaDateRanges[id].attr)}"`); }); return dateRanges; } function mapPartIntersection(oldParts, newParts, intersectionFn) { if (oldParts && newParts) { let delta = 0; for (let i = 0, len = oldParts.length; i <= len; i++) { const oldPart = oldParts[i]; const newPart = newParts[i + delta]; if (oldPart && newPart && oldPart.index === newPart.index && oldPart.fragment.sn === newPart.fragment.sn) intersectionFn(oldPart, newPart); else delta--; } } } function mapFragmentIntersection(oldDetails, newDetails, intersectionFn) { const skippedSegments = newDetails.skippedSegments; const start = Math.max(oldDetails.startSN, newDetails.startSN) - newDetails.startSN; const end = (oldDetails.fragmentHint ? 1 : 0) + (skippedSegments ? newDetails.endSN : Math.min(oldDetails.endSN, newDetails.endSN)) - newDetails.startSN; const delta = newDetails.startSN - oldDetails.startSN; const newFrags = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments; const oldFrags = oldDetails.fragmentHint ? oldDetails.fragments.concat(oldDetails.fragmentHint) : oldDetails.fragments; for (let i = start; i <= end; i++) { const oldFrag = oldFrags[delta + i]; let newFrag = newFrags[i]; if (skippedSegments && !newFrag && oldFrag) newFrag = newDetails.fragments[i] = oldFrag; if (oldFrag && newFrag) { intersectionFn(oldFrag, newFrag, i, newFrags); const uriBefore = oldFrag.relurl; const uriAfter = newFrag.relurl; if (uriBefore && notEqualAfterStrippingQueries(uriBefore, uriAfter)) { newDetails.playlistParsingError = getSequenceError(`media sequence mismatch ${newFrag.sn}:`, oldDetails, newDetails, oldFrag, newFrag); return; } else if (oldFrag.cc !== newFrag.cc) { newDetails.playlistParsingError = getSequenceError(`discontinuity sequence mismatch (${oldFrag.cc}!=${newFrag.cc})`, oldDetails, newDetails, oldFrag, newFrag); return; } } } } function getSequenceError(message, oldDetails, newDetails, oldFrag, newFrag) { return /* @__PURE__ */ new Error(`${message} ${newFrag.url} Playlist starting @${oldDetails.startSN} ${oldDetails.m3u8} Playlist starting @${newDetails.startSN} ${newDetails.m3u8}`); } function adjustSliding(oldDetails, newDetails, matchingStableVariantOrRendition = true) { const delta = newDetails.startSN + newDetails.skippedSegments - oldDetails.startSN; const oldFragments = oldDetails.fragments; const advancedOrStable = delta >= 0; let sliding = 0; if (advancedOrStable && delta < oldFragments.length) sliding = oldFragments[delta].start; else if (advancedOrStable && newDetails.startSN === oldDetails.endSN + 1) sliding = oldDetails.fragmentEnd; else if (advancedOrStable && matchingStableVariantOrRendition) sliding = oldDetails.fragmentStart + delta * newDetails.levelTargetDuration; else if (!newDetails.skippedSegments && newDetails.fragmentStart === 0) sliding = oldDetails.fragmentStart; else return; addSliding(newDetails, sliding); } function addSliding(details, sliding) { if (sliding) { const fragments = details.fragments; for (let i = details.skippedSegments; i < fragments.length; i++) fragments[i].addStart(sliding); if (details.fragmentHint) details.fragmentHint.addStart(sliding); } } function computeReloadInterval(newDetails, distanceToLiveEdgeMs = Infinity) { let reloadInterval = 1e3 * newDetails.targetduration; if (newDetails.updated) { const fragments = newDetails.fragments; if (fragments.length && reloadInterval * 4 > distanceToLiveEdgeMs) { const lastSegmentDuration = fragments[fragments.length - 1].duration * 1e3; if (lastSegmentDuration < reloadInterval) reloadInterval = lastSegmentDuration; } } else reloadInterval /= 2; return Math.round(reloadInterval); } function getFragmentWithSN(details, sn, fragCurrent) { if (!details) return null; let fragment = details.fragments[sn - details.startSN]; if (fragment) return fragment; fragment = details.fragmentHint; if (fragment && fragment.sn === sn) return fragment; if (sn < details.startSN && fragCurrent && fragCurrent.sn === sn) return fragCurrent; return null; } function getPartWith(details, sn, partIndex) { if (!details) return null; return findPart(details.partList, sn, partIndex); } function findPart(partList, sn, partIndex) { if (partList) for (let i = partList.length; i--;) { const part = partList[i]; if (part.index === partIndex && part.fragment.sn === sn) return part; } return null; } function reassignFragmentLevelIndexes(levels) { levels.forEach((level, index) => { var _level$details; (_level$details = level.details) == null || _level$details.fragments.forEach((fragment) => { fragment.level = index; if (fragment.initSegment) fragment.initSegment.level = index; }); }); } function notEqualAfterStrippingQueries(uriBefore, uriAfter) { if (uriBefore !== uriAfter && uriAfter) return stripQuery(uriBefore) !== stripQuery(uriAfter); return false; } function stripQuery(uri) { return uri.replace(/\?[^?]*$/, ""); } function findFirstFragWithCC(fragments, cc) { for (let i = 0, len = fragments.length; i < len; i++) { var _fragments$i; if (((_fragments$i = fragments[i]) == null ? void 0 : _fragments$i.cc) === cc) return fragments[i]; } return null; } function shouldAlignOnDiscontinuities(refDetails, details) { if (refDetails) { if (details.startCC < refDetails.endCC && details.endCC > refDetails.startCC) return true; } return false; } function adjustFragmentStart(frag, sliding) { const start = frag.start + sliding; frag.startPTS = start; frag.setStart(start); frag.endPTS = start + frag.duration; } function adjustSlidingStart(sliding, details) { const fragments = details.fragments; for (let i = 0, len = fragments.length; i < len; i++) adjustFragmentStart(fragments[i], sliding); if (details.fragmentHint) adjustFragmentStart(details.fragmentHint, sliding); details.alignedSliding = true; } /** * Using the parameters of the last level, this function computes PTS' of the new fragments so that they form a * contiguous stream with the last fragments. * The PTS of a fragment lets Hls.js know where it fits into a stream - by knowing every PTS, we know which fragment to * download at any given time. PTS is normally computed when the fragment is demuxed, so taking this step saves us time * and an extra download. * @param lastLevel * @param details */ function alignStream(switchDetails, details) { if (!switchDetails) return; alignDiscontinuities(details, switchDetails); if (!details.alignedSliding) alignMediaPlaylistByPDT(details, switchDetails); if (!details.alignedSliding && !details.skippedSegments) adjustSliding(switchDetails, details, false); } /** * Ajust the start of fragments in `details` by the difference in time between fragments of the latest * shared discontinuity sequence change. * @param lastLevel - The details of the last loaded level * @param details - The details of the new level */ function alignDiscontinuities(details, refDetails) { if (!shouldAlignOnDiscontinuities(refDetails, details)) return; const targetCC = Math.min(refDetails.endCC, details.endCC); const refFrag = findFirstFragWithCC(refDetails.fragments, targetCC); const frag = findFirstFragWithCC(details.fragments, targetCC); if (!refFrag || !frag) return; logger.log(`Aligning playlist at start of dicontinuity sequence ${targetCC}`); adjustSlidingStart(refFrag.start - frag.start, details); } /** * Ensures appropriate time-alignment between renditions based on PDT. * This function assumes the timelines represented in `refDetails` are accurate, including the PDTs * for the last discontinuity sequence number shared by both playlists when present, * and uses the "wallclock"/PDT timeline as a cross-reference to `details`, adjusting the presentation * times/timelines of `details` accordingly. * Given the asynchronous nature of fetches and initial loads of live `main` and audio/subtitle tracks, * the primary purpose of this function is to ensure the "local timelines" of audio/subtitle tracks * are aligned to the main/video timeline, using PDT as the cross-reference/"anchor" that should * be consistent across playlists, per the HLS spec. * @param details - The details of the rendition you'd like to time-align (e.g. an audio rendition). * @param refDetails - The details of the reference rendition with start and PDT times for alignment. */ function alignMediaPlaylistByPDT(details, refDetails) { if (!details.hasProgramDateTime || !refDetails.hasProgramDateTime) return; const fragments = details.fragments; const refFragments = refDetails.fragments; if (!fragments.length || !refFragments.length) return; let refFrag; let frag; const targetCC = Math.min(refDetails.endCC, details.endCC); if (refDetails.startCC < targetCC && details.startCC < targetCC) { refFrag = findFirstFragWithCC(refFragments, targetCC); frag = findFirstFragWithCC(fragments, targetCC); } if (!refFrag || !frag) { refFrag = refFragments[Math.floor(refFragments.length / 2)]; frag = findFirstFragWithCC(fragments, refFrag.cc) || fragments[Math.floor(fragments.length / 2)]; } const refPDT = refFrag.programDateTime; const targetPDT = frag.programDateTime; if (!refPDT || !targetPDT) return; adjustSlidingStart((targetPDT - refPDT) / 1e3 - (frag.start - refFrag.start), details); } function addEventListener(el, type, listener) { removeEventListener(el, type, listener); el.addEventListener(type, listener); } function removeEventListener(el, type, listener) { el.removeEventListener(type, listener); } /** * TimeRanges to string helper */ var TimeRanges = { toString: function(r) { let log = ""; const len = r.length; for (let i = 0; i < len; i++) log += `[${r.start(i).toFixed(3)}-${r.end(i).toFixed(3)}]`; return log; } }; var State = { STOPPED: "STOPPED", IDLE: "IDLE", KEY_LOADING: "KEY_LOADING", FRAG_LOADING: "FRAG_LOADING", FRAG_LOADING_WAITING_RETRY: "FRAG_LOADING_WAITING_RETRY", WAITING_TRACK: "WAITING_TRACK", PARSING: "PARSING", PARSED: "PARSED", ENDED: "ENDED", ERROR: "ERROR", WAITING_INIT_PTS: "WAITING_INIT_PTS", WAITING_LEVEL: "WAITING_LEVEL" }; var BaseStreamController = class extends TaskLoop { constructor(hls, fragmentTracker, keyLoader, logPrefix, playlistType) { super(logPrefix, hls.logger); this.hls = void 0; this.fragPrevious = null; this.fragCurrent = null; this.fragmentTracker = void 0; this.transmuxer = null; this._state = State.STOPPED; this.playlistType = void 0; this.media = null; this.mediaBuffer = null; this.config = void 0; this.bitrateTest = false; this.lastCurrentTime = 0; this.nextLoadPosition = 0; this.startPosition = 0; this.startTimeOffset = null; this.retryDate = 0; this.levels = null; this.fragmentLoader = void 0; this.keyLoader = void 0; this.levelLastLoaded = null; this.startFragRequested = false; this.decrypter = void 0; this.initPTS = []; this.buffering = true; this.loadingParts = false; this.loopSn = void 0; this.onMediaSeeking = () => { const { config, fragCurrent, media, mediaBuffer, state } = this; const currentTime = media ? media.currentTime : 0; const bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole); const noFowardBuffer = !bufferInfo.len; this.log(`Media seeking to ${isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime}, state: ${state}, ${noFowardBuffer ? "out of" : "in"} buffer`); if (this.state === State.ENDED) this.resetLoadingState(); else if (fragCurrent) { const tolerance = config.maxFragLookUpTolerance; const fragStartOffset = fragCurrent.start - tolerance; const fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance; if (noFowardBuffer || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) { const pastFragment = currentTime > fragEndOffset; if (currentTime < fragStartOffset || pastFragment) { if (pastFragment && fragCurrent.loader) { this.log(`Cancelling fragment load for seek (sn: ${fragCurrent.sn})`); fragCurrent.abortRequests(); this.resetLoadingState(); } this.fragPrevious = null; } } } if (media) { this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true); if (currentTime > this.lastCurrentTime) this.lastCurrentTime = currentTime; if (!this.loadingParts) { const bufferEnd = Math.max(bufferInfo.end, currentTime); const shouldLoadParts = this.shouldLoadParts(this.getLevelDetails(), bufferEnd); if (shouldLoadParts) { this.log(`LL-Part loading ON after seeking to ${currentTime.toFixed(2)} with buffer @${bufferEnd.toFixed(2)}`); this.loadingParts = shouldLoadParts; } } } if (!this.hls.hasEnoughToStart) { this.log(`Setting ${noFowardBuffer ? "startPosition" : "nextLoadPosition"} to ${currentTime} for seek without enough to start`); this.nextLoadPosition = currentTime; if (noFowardBuffer) this.startPosition = currentTime; } if (noFowardBuffer && this.state === State.IDLE) this.tickImmediate(); }; this.onMediaEnded = () => { this.log(`setting startPosition to 0 because media ended`); this.startPosition = this.lastCurrentTime = 0; }; this.playlistType = playlistType; this.hls = hls; this.fragmentLoader = new FragmentLoader(hls.config); this.keyLoader = keyLoader; this.fragmentTracker = fragmentTracker; this.config = hls.config; this.decrypter = new Decrypter(hls.config); } registerListeners() { const { hls } = this; hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const { hls } = this; hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); hls.off(Events.ERROR, this.onError, this); } doTick() { this.onTickEnd(); } onTickEnd() {} startLoad(startPosition) {} stopLoad() { if (this.state === State.STOPPED) return; this.fragmentLoader.abort(); this.keyLoader.abort(this.playlistType); const frag = this.fragCurrent; if (frag != null && frag.loader) { frag.abortRequests(); this.fragmentTracker.removeFragment(frag); } this.resetTransmuxer(); this.fragCurrent = null; this.fragPrevious = null; this.clearInterval(); this.clearNextTick(); this.state = State.STOPPED; } get startPositionValue() { const { nextLoadPosition, startPosition } = this; if (startPosition === -1 && nextLoadPosition) return nextLoadPosition; return startPosition; } get bufferingEnabled() { return this.buffering; } pauseBuffering() { this.buffering = false; } resumeBuffering() { this.buffering = true; } get inFlightFrag() { return { frag: this.fragCurrent, state: this.state }; } _streamEnded(bufferInfo, levelDetails) { if (levelDetails.live || !this.media) return false; const bufferEnd = bufferInfo.end || 0; const timelineStart = this.config.timelineOffset || 0; if (bufferEnd <= timelineStart) return false; const bufferedRanges = bufferInfo.buffered; if (this.config.maxBufferHole && bufferedRanges && bufferedRanges.length > 1) bufferInfo = BufferHelper.bufferedInfo(bufferedRanges, bufferInfo.start, 0); const nextStart = bufferInfo.nextStart; if (nextStart && nextStart > timelineStart && nextStart < levelDetails.edge) return false; if (this.media.currentTime < bufferInfo.start) return false; const partList = levelDetails.partList; if (partList != null && partList.length) { const lastPart = partList[partList.length - 1]; return BufferHelper.isBuffered(this.media, lastPart.start + lastPart.duration / 2); } const playlistType = levelDetails.fragments[levelDetails.fragments.length - 1].type; return this.fragmentTracker.isEndListAppended(playlistType); } getLevelDetails() { if (this.levels && this.levelLastLoaded !== null) return this.levelLastLoaded.details; } get timelineOffset() { const configuredTimelineOffset = this.config.timelineOffset; if (configuredTimelineOffset) { var _this$getLevelDetails; return ((_this$getLevelDetails = this.getLevelDetails()) == null ? void 0 : _this$getLevelDetails.appliedTimelineOffset) || configuredTimelineOffset; } return 0; } onMediaAttached(event, data) { const media = this.media = this.mediaBuffer = data.media; addEventListener(media, "seeking", this.onMediaSeeking); addEventListener(media, "ended", this.onMediaEnded); const config = this.config; if (this.levels && config.autoStartLoad && this.state === State.STOPPED) this.startLoad(config.startPosition); } onMediaDetaching(event, data) { const transferringMedia = !!data.transferMedia; const media = this.media; if (media === null) return; if (media.ended) { this.log("MSE detaching and video ended, reset startPosition"); this.startPosition = this.lastCurrentTime = 0; } removeEventListener(media, "seeking", this.onMediaSeeking); removeEventListener(media, "ended", this.onMediaEnded); if (this.keyLoader && !transferringMedia) this.keyLoader.detach(); this.media = this.mediaBuffer = null; this.loopSn = void 0; if (transferringMedia) { this.resetLoadingState(); this.resetTransmuxer(); return; } this.loadingParts = false; this.fragmentTracker.removeAllFragments(); this.stopLoad(); } onManifestLoading() { this.initPTS = []; this.levels = this.levelLastLoaded = this.fragCurrent = null; this.lastCurrentTime = this.startPosition = 0; this.startFragRequested = false; } onError(event, data) {} onManifestLoaded(event, data) { this.startTimeOffset = data.startTimeOffset; } onHandlerDestroying() { this.stopLoad(); if (this.transmuxer) { this.transmuxer.destroy(); this.transmuxer = null; } super.onHandlerDestroying(); this.hls = this.onMediaSeeking = this.onMediaEnded = null; } onHandlerDestroyed() { this.state = State.STOPPED; if (this.fragmentLoader) this.fragmentLoader.destroy(); if (this.keyLoader) this.keyLoader.destroy(); if (this.decrypter) this.decrypter.destroy(); this.hls = this.log = this.warn = this.decrypter = this.keyLoader = this.fragmentLoader = this.fragmentTracker = null; super.onHandlerDestroyed(); } loadFragment(frag, level, targetBufferTime) { this.startFragRequested = true; this._loadFragForPlayback(frag, level, targetBufferTime); } _loadFragForPlayback(fragment, level, targetBufferTime) { const progressCallback = (data) => { const frag = data.frag; if (this.fragContextChanged(frag)) { this.warn(`${frag.type} sn: ${frag.sn}${data.part ? " part: " + data.part.index : ""} of ${this.fragInfo(frag, false, data.part)}) was dropped during download.`); this.fragmentTracker.removeFragment(frag); return; } frag.stats.chunkCount++; this._handleFragmentLoadProgress(data); }; this._doFragLoad(fragment, level, targetBufferTime, progressCallback).then((data) => { if (!data) return; const state = this.state; const frag = data.frag; if (this.fragContextChanged(frag)) { if (state === State.FRAG_LOADING || !this.fragCurrent && state === State.PARSING) { this.fragmentTracker.removeFragment(frag); this.state = State.IDLE; } return; } if ("payload" in data) { this.log(`Loaded ${frag.type} sn: ${frag.sn} of ${this.playlistLabel()} ${frag.level}`); this.hls.trigger(Events.FRAG_LOADED, data); } this._handleFragmentLoadComplete(data); }).catch((reason) => { if (this.state === State.STOPPED || this.state === State.ERROR) return; this.warn(`Frag error: ${(reason == null ? void 0 : reason.message) || reason}`); this.resetFragmentLoading(fragment); }); } clearTrackerIfNeeded(frag) { var _this$mediaBuffer; const { fragmentTracker } = this; if (fragmentTracker.getState(frag) === FragmentState.APPENDING) { const playlistType = frag.type; const bufferedInfo = this.getFwdBufferInfo(this.mediaBuffer, playlistType); const minForwardBufferLength = Math.max(frag.duration, bufferedInfo ? bufferedInfo.len : this.config.maxBufferLength); const backtrackFragment = this.backtrackFragment; if ((backtrackFragment ? frag.sn - backtrackFragment.sn : 0) === 1 || this.reduceMaxBufferLength(minForwardBufferLength, frag.duration)) fragmentTracker.removeFragment(frag); } else if (((_this$mediaBuffer = this.mediaBuffer) == null ? void 0 : _this$mediaBuffer.buffered.length) === 0) fragmentTracker.removeAllFragments(); else if (fragmentTracker.hasParts(frag.type)) { fragmentTracker.detectPartialFragments({ frag, part: null, stats: frag.stats, id: frag.type }); if (fragmentTracker.getState(frag) === FragmentState.PARTIAL) fragmentTracker.removeFragment(frag); } } checkLiveUpdate(details) { if (details.updated && !details.live) { const lastFragment = details.fragments[details.fragments.length - 1]; this.fragmentTracker.detectPartialFragments({ frag: lastFragment, part: null, stats: lastFragment.stats, id: lastFragment.type }); } if (!details.fragments[0]) details.deltaUpdateFailed = true; } waitForLive(levelInfo) { const details = levelInfo.details; return (details == null ? void 0 : details.live) && details.type !== "EVENT" && (this.levelLastLoaded !== levelInfo || details.expired); } flushMainBuffer(startOffset, endOffset, type = null) { if (!(startOffset - endOffset)) return; const flushScope = { startOffset, endOffset, type }; this.hls.trigger(Events.BUFFER_FLUSHING, flushScope); } _loadInitSegment(fragment, level) { this._doFragLoad(fragment, level).then((data) => { const frag = data == null ? void 0 : data.frag; if (!frag || this.fragContextChanged(frag) || !this.levels) throw new Error("init load aborted"); return data; }).then((data) => { const { hls } = this; const { frag, payload } = data; const decryptData = frag.decryptdata; if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) { const startTime = self.performance.now(); return this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch((err) => { hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_DECRYPT_ERROR, fatal: false, error: err, reason: err.message, frag }); throw err; }).then((decryptedData) => { const endTime = self.performance.now(); hls.trigger(Events.FRAG_DECRYPTED, { frag, payload: decryptedData, stats: { tstart: startTime, tdecrypt: endTime } }); data.payload = decryptedData; return this.completeInitSegmentLoad(data); }); } return this.completeInitSegmentLoad(data); }).catch((reason) => { if (this.state === State.STOPPED || this.state === State.ERROR) return; this.warn(reason); this.resetFragmentLoading(fragment); }); } completeInitSegmentLoad(data) { const { levels } = this; if (!levels) throw new Error("init load aborted, missing levels"); const stats = data.frag.stats; if (this.state !== State.STOPPED) this.state = State.IDLE; data.frag.data = new Uint8Array(data.payload); stats.parsing.start = stats.buffering.start = self.performance.now(); stats.parsing.end = stats.buffering.end = self.performance.now(); this.tick(); } unhandledEncryptionError(initSegment, frag) { var _tracks$audio, _tracks$video; const tracks = initSegment.tracks; if (tracks && !frag.encrypted && ((_tracks$audio = tracks.audio) != null && _tracks$audio.encrypted || (_tracks$video = tracks.video) != null && _tracks$video.encrypted) && (!this.config.emeEnabled || !this.keyLoader.emeController)) { const media = this.media; const error = /* @__PURE__ */ new Error(`Encrypted track with no key in ${this.fragInfo(frag)} (media ${media ? "attached mediaKeys: " + media.mediaKeys : "detached"})`); this.warn(error.message); if (!media || media.mediaKeys) return false; this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_KEYS, fatal: false, error, frag }); this.resetTransmuxer(); return true; } return false; } fragContextChanged(frag) { const { fragCurrent } = this; return !frag || !fragCurrent || frag.sn !== fragCurrent.sn || frag.level !== fragCurrent.level; } fragBufferedComplete(frag, part) { const media = this.mediaBuffer ? this.mediaBuffer : this.media; this.log(`Buffered ${frag.type} sn: ${frag.sn}${part ? " part: " + part.index : ""} of ${this.fragInfo(frag, false, part)} > buffer:${media ? TimeRanges.toString(BufferHelper.getBuffered(media)) : "(detached)"})`); if (isMediaFragment(frag)) { var _this$levels; if (frag.type !== PlaylistLevelType.SUBTITLE) { const el = frag.elementaryStreams; if (!Object.keys(el).some((type) => !!el[type])) { this.state = State.IDLE; return; } } const level = (_this$levels = this.levels) == null ? void 0 : _this$levels[frag.level]; if (level != null && level.fragmentError) { this.log(`Resetting level fragment error count of ${level.fragmentError} on frag buffered`); level.fragmentError = 0; } } this.state = State.IDLE; } _handleFragmentLoadComplete(fragLoadedEndData) { const { transmuxer } = this; if (!transmuxer) return; const { frag, part, partsLoaded } = fragLoadedEndData; const complete = !partsLoaded || partsLoaded.length === 0 || partsLoaded.some((fragLoaded) => !fragLoaded); const chunkMeta = new ChunkMetadata(frag.level, frag.sn, frag.stats.chunkCount + 1, 0, part ? part.index : -1, !complete); transmuxer.flush(chunkMeta); } _handleFragmentLoadProgress(frag) {} _doFragLoad(frag, level, targetBufferTime = null, progressCallback) { var _frag$decryptdata; this.fragCurrent = frag; const details = level.details; if (!this.levels || !details) throw new Error(`frag load aborted, missing level${details ? "" : " detail"}s`); let keyLoadingPromise = null; if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) { this.log(`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${this.playlistLabel()} ${frag.level}`); this.state = State.KEY_LOADING; this.fragCurrent = frag; keyLoadingPromise = this.keyLoader.load(frag).then((keyLoadedData) => { if (!this.fragContextChanged(keyLoadedData.frag)) { this.hls.trigger(Events.KEY_LOADED, keyLoadedData); if (this.state === State.KEY_LOADING) this.state = State.IDLE; return keyLoadedData; } }); this.hls.trigger(Events.KEY_LOADING, { frag }); if (this.fragCurrent === null) { this.log(`context changed in KEY_LOADING`); return Promise.resolve(null); } } else if (!frag.encrypted) { keyLoadingPromise = this.keyLoader.loadClear(frag, details.encryptedFragments, this.startFragRequested); if (keyLoadingPromise) this.log(`[eme] blocking frag load until media-keys acquired`); } const fragPrevious = this.fragPrevious; if (isMediaFragment(frag) && (!fragPrevious || frag.sn !== fragPrevious.sn)) { const shouldLoadParts = this.shouldLoadParts(level.details, frag.end); if (shouldLoadParts !== this.loadingParts) { this.log(`LL-Part loading ${shouldLoadParts ? "ON" : "OFF"} loading sn ${fragPrevious == null ? void 0 : fragPrevious.sn}->${frag.sn}`); this.loadingParts = shouldLoadParts; } } targetBufferTime = Math.max(frag.start, targetBufferTime || 0); if (this.loadingParts && isMediaFragment(frag)) { const partList = details.partList; if (partList && progressCallback) { if (targetBufferTime > details.fragmentEnd && details.fragmentHint) frag = details.fragmentHint; const partIndex = this.getNextPart(partList, frag, targetBufferTime); if (partIndex > -1) { const part = partList[partIndex]; frag = this.fragCurrent = part.fragment; this.log(`Loading ${frag.type} sn: ${frag.sn} part: ${part.index} (${partIndex}/${partList.length - 1}) of ${this.fragInfo(frag, false, part)}) cc: ${frag.cc} [${details.startSN}-${details.endSN}], target: ${parseFloat(targetBufferTime.toFixed(3))}`); this.nextLoadPosition = part.start + part.duration; this.state = State.FRAG_LOADING; let _result; if (keyLoadingPromise) _result = keyLoadingPromise.then((keyLoadedData) => { if (!keyLoadedData || this.fragContextChanged(keyLoadedData.frag)) return null; return this.doFragPartsLoad(frag, part, level, progressCallback); }).catch((error) => this.handleFragLoadError(error)); else _result = this.doFragPartsLoad(frag, part, level, progressCallback).catch((error) => this.handleFragLoadError(error)); this.hls.trigger(Events.FRAG_LOADING, { frag, part, targetBufferTime }); if (this.fragCurrent === null) return Promise.reject(/* @__PURE__ */ new Error(`frag load aborted, context changed in FRAG_LOADING parts`)); return _result; } else if (!frag.url || this.loadedEndOfParts(partList, targetBufferTime)) return Promise.resolve(null); } } if (isMediaFragment(frag) && this.loadingParts) { var _details$partList; this.log(`LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(2)} Check buffer at sn: ${frag.sn} loaded parts: ${(_details$partList = details.partList) == null ? void 0 : _details$partList.filter((p) => p.loaded).map((p) => `[${p.start}-${p.end}]`)}`); this.loadingParts = false; } else if (!frag.url) return Promise.resolve(null); this.log(`Loading ${frag.type} sn: ${frag.sn} of ${this.fragInfo(frag, false)}) cc: ${frag.cc} ${"[" + details.startSN + "-" + details.endSN + "]"}, target: ${parseFloat(targetBufferTime.toFixed(3))}`); if (isFiniteNumber(frag.sn) && !this.bitrateTest) this.nextLoadPosition = frag.start + frag.duration; this.state = State.FRAG_LOADING; const dataOnProgress = this.config.progressive && frag.type !== PlaylistLevelType.SUBTITLE; let result; if (dataOnProgress && keyLoadingPromise) result = keyLoadingPromise.then((keyLoadedData) => { if (!keyLoadedData || this.fragContextChanged(keyLoadedData.frag)) return null; return this.fragmentLoader.load(frag, progressCallback); }).catch((error) => this.handleFragLoadError(error)); else result = Promise.all([this.fragmentLoader.load(frag, dataOnProgress ? progressCallback : void 0), keyLoadingPromise]).then(([fragLoadedData]) => { if (!dataOnProgress && progressCallback) progressCallback(fragLoadedData); return fragLoadedData; }).catch((error) => this.handleFragLoadError(error)); this.hls.trigger(Events.FRAG_LOADING, { frag, targetBufferTime }); if (this.fragCurrent === null) return Promise.reject(/* @__PURE__ */ new Error(`frag load aborted, context changed in FRAG_LOADING`)); return result; } doFragPartsLoad(frag, fromPart, level, progressCallback) { return new Promise((resolve, reject) => { var _level$details; const partsLoaded = []; const initialPartList = (_level$details = level.details) == null ? void 0 : _level$details.partList; const loadPart = (part) => { this.fragmentLoader.loadPart(frag, part, progressCallback).then((partLoadedData) => { partsLoaded[part.index] = partLoadedData; const loadedPart = partLoadedData.part; this.hls.trigger(Events.FRAG_LOADED, partLoadedData); const nextPart = getPartWith(level.details, frag.sn, part.index + 1) || findPart(initialPartList, frag.sn, part.index + 1); if (nextPart) loadPart(nextPart); else return resolve({ frag, part: loadedPart, partsLoaded }); }).catch(reject); }; loadPart(fromPart); }); } handleFragLoadError(error) { if ("data" in error) { const data = error.data; if (data.frag && data.details === ErrorDetails.INTERNAL_ABORTED) this.handleFragLoadAborted(data.frag, data.part); else if (data.frag && data.type === ErrorTypes.KEY_SYSTEM_ERROR) { data.frag.abortRequests(); this.resetStartWhenNotLoaded(); this.resetFragmentLoading(data.frag); } else this.hls.trigger(Events.ERROR, data); } else this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.INTERNAL_EXCEPTION, err: error, error, fatal: true }); return null; } _handleTransmuxerFlush(chunkMeta) { const context = this.getCurrentContext(chunkMeta); if (!context || this.state !== State.PARSING) { if (!this.fragCurrent && this.state !== State.STOPPED && this.state !== State.ERROR) this.state = State.IDLE; return; } const { frag, part, level } = context; const now = self.performance.now(); frag.stats.parsing.end = now; if (part) part.stats.parsing.end = now; const levelDetails = this.getLevelDetails(); const shouldLoadParts = levelDetails && frag.sn > levelDetails.endSN || this.shouldLoadParts(levelDetails, frag.end); if (shouldLoadParts !== this.loadingParts) { this.log(`LL-Part loading ${shouldLoadParts ? "ON" : "OFF"} after parsing segment ending @${frag.end.toFixed(2)}`); this.loadingParts = shouldLoadParts; } this.updateLevelTiming(frag, part, level, chunkMeta.partial); } shouldLoadParts(details, bufferEnd) { if (this.config.lowLatencyMode) { if (!details) return this.loadingParts; if (details.partList) { var _details$fragmentHint; const firstPart = details.partList[0]; if (firstPart.fragment.type === PlaylistLevelType.SUBTITLE) return false; if (bufferEnd >= firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0)) { var _this$media; if ((this.hls.hasEnoughToStart ? ((_this$media = this.media) == null ? void 0 : _this$media.currentTime) || this.lastCurrentTime : this.getLoadPosition()) > firstPart.start - firstPart.fragment.duration) return true; } } } return false; } getCurrentContext(chunkMeta) { const { levels, fragCurrent } = this; const { level: levelIndex, sn, part: partIndex } = chunkMeta; if (!(levels != null && levels[levelIndex])) { this.warn(`Levels object was unset while buffering fragment ${sn} of ${this.playlistLabel()} ${levelIndex}. The current chunk will not be buffered.`); return null; } const level = levels[levelIndex]; const levelDetails = level.details; const part = partIndex > -1 ? getPartWith(levelDetails, sn, partIndex) : null; const frag = part ? part.fragment : getFragmentWithSN(levelDetails, sn, fragCurrent); if (!frag) return null; if (fragCurrent && fragCurrent !== frag) frag.stats = fragCurrent.stats; return { frag, part, level }; } bufferFragmentData(data, frag, part, chunkMeta, noBacktracking) { if (this.state !== State.PARSING) return; const { data1, data2 } = data; let buffer = data1; if (data2) buffer = appendUint8Array(data1, data2); if (!buffer.length) return; const offsetTimestamp = this.initPTS[frag.cc]; const offset = offsetTimestamp ? -offsetTimestamp.baseTime / offsetTimestamp.timescale : void 0; const segment = { type: data.type, frag, part, chunkMeta, offset, parent: frag.type, data: buffer }; this.hls.trigger(Events.BUFFER_APPENDING, segment); if (data.dropped && data.independent && !part) { if (noBacktracking) return; this.flushBufferGap(frag); } } flushBufferGap(frag) { const media = this.media; if (!media) return; if (!BufferHelper.isBuffered(media, media.currentTime)) { this.flushMainBuffer(0, frag.start); return; } const currentTime = media.currentTime; const bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0); const fragDuration = frag.duration; const segmentFraction = Math.min(this.config.maxFragLookUpTolerance * 2, fragDuration * .25); const start = Math.max(Math.min(frag.start - segmentFraction, bufferInfo.end - segmentFraction), currentTime + segmentFraction); if (frag.start - start > segmentFraction) this.flushMainBuffer(start, frag.start); } getFwdBufferInfo(bufferable, type) { var _this$media2; const pos = this.getLoadPosition(); if (!isFiniteNumber(pos)) return null; const maxBufferHole = this.lastCurrentTime > pos || (_this$media2 = this.media) != null && _this$media2.paused ? 0 : this.config.maxBufferHole; return this.getFwdBufferInfoAtPos(bufferable, pos, type, maxBufferHole); } getFwdBufferInfoAtPos(bufferable, pos, type, maxBufferHole) { const bufferInfo = BufferHelper.bufferInfo(bufferable, pos, maxBufferHole); if (bufferInfo.len === 0 && bufferInfo.nextStart !== void 0) { const bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type); if (bufferedFragAtPos && (bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)) { const gapDuration = Math.max(Math.min(bufferInfo.nextStart, bufferedFragAtPos.end) - pos, maxBufferHole); return BufferHelper.bufferInfo(bufferable, pos, gapDuration); } } return bufferInfo; } getMaxBufferLength(levelBitrate) { const { config } = this; let maxBufLen; if (levelBitrate) maxBufLen = Math.max(8 * config.maxBufferSize / levelBitrate, config.maxBufferLength); else maxBufLen = config.maxBufferLength; return Math.min(maxBufLen, config.maxMaxBufferLength); } exceedsMaxBuffer(bufferInfo, maxBufLen, selected) { const nextStart = bufferInfo.nextStart; if (nextStart && selected.start > nextStart) { const bufferedRanges = bufferInfo.buffered; if (bufferedRanges) { let fullBufferLength = bufferInfo.len; const bufferedIndex = bufferInfo.bufferedIndex; for (let i = bufferedRanges.length - 1; i > bufferedIndex; i--) if (bufferedRanges[i].start < selected.start) fullBufferLength += bufferedRanges[i].end - bufferedRanges[i].start; return fullBufferLength >= maxBufLen; } } return false; } reduceMaxBufferLength(threshold, fragDuration) { const config = this.config; const minLength = Math.max(Math.min(threshold - fragDuration, config.maxBufferLength), fragDuration); const reducedLength = Math.max(threshold - fragDuration * 3, config.maxMaxBufferLength / 2, minLength); if (reducedLength >= minLength) { config.maxMaxBufferLength = reducedLength; this.warn(`Reduce max buffer length to ${reducedLength}s`); return true; } return false; } getAppendedFrag(position, playlistType = PlaylistLevelType.MAIN) { const fragOrPart = this.fragmentTracker ? this.fragmentTracker.getAppendedFrag(position, playlistType) : null; if (fragOrPart && "fragment" in fragOrPart) return fragOrPart.fragment; return fragOrPart; } getNextFragment(pos, levelDetails) { const fragments = levelDetails.fragments; const fragLen = fragments.length; if (!fragLen) return null; const { config } = this; const playlistStart = levelDetails.fragmentStart; const canLoadParts = config.lowLatencyMode && !!levelDetails.partList; let frag = null; if (levelDetails.live) { const initialLiveManifestSize = config.initialLiveManifestSize; if (fragLen < initialLiveManifestSize) { this.warn(`Not enough fragments to start playback (have: ${fragLen}, need: ${initialLiveManifestSize})`); return null; } if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < playlistStart) { var _frag; if (canLoadParts && !this.loadingParts) { this.log(`LL-Part loading ON for initial live fragment`); this.loadingParts = true; } frag = this.getInitialLiveFragment(levelDetails); const configValue = this.config.startPosition; const mainStart = this.hls.startPosition; const liveSyncPosition = this.hls.liveSyncPosition; const fragStart = ((_frag = frag) == null ? void 0 : _frag.start) || 0; let startPosition; let reason; if (mainStart !== -1 && mainStart >= playlistStart) { startPosition = mainStart; reason = mainStart === configValue ? "config" : "next load start"; } else if (liveSyncPosition !== null) { startPosition = liveSyncPosition; reason = "live edge"; } else { startPosition = pos; reason = "buffer pos"; } if (startPosition < fragStart) { startPosition = fragStart; reason = "live frag start"; } if (startPosition < playlistStart) { startPosition = playlistStart; reason = "playlist start"; } if (this.startPosition != startPosition || this.nextLoadPosition != startPosition) { this.log(`Setting startPosition to ${startPosition.toFixed(3)} ${mainStart === -1 ? "" : `(from ${configValue}) `}based on ${reason}. live edge: ${liveSyncPosition} live frag start: ${fragStart.toFixed(3)} playlist start: ${playlistStart.toFixed(3)} buffer pos: ${pos}`); this.startPosition = this.nextLoadPosition = startPosition; } } } else if (pos <= playlistStart) frag = fragments[0]; if (!frag) { const end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd; frag = this.getFragmentAtPosition(pos, end, levelDetails); } let programFrag = this.filterReplacedPrimary(frag, levelDetails); if (!programFrag && frag) { const curSNIdx = frag.sn - levelDetails.startSN; programFrag = this.filterReplacedPrimary(fragments[curSNIdx + 1] || null, levelDetails); } return this.mapToInitFragWhenRequired(programFrag); } isLoopLoading(frag, targetBufferTime) { if (this.nextLoadPosition <= targetBufferTime) return false; const trackerState = this.fragmentTracker.getState(frag); return trackerState === FragmentState.OK || trackerState === FragmentState.PARTIAL && !!frag.gap; } getNextFragmentLoopLoading(frag, levelDetails, bufferInfo, playlistType, maxBufLen) { let nextFragment = null; if (frag.gap) { nextFragment = this.getNextFragment(this.nextLoadPosition, levelDetails); if (nextFragment && !nextFragment.gap && bufferInfo.nextStart) { const nextbufferInfo = this.getFwdBufferInfoAtPos(this.mediaBuffer ? this.mediaBuffer : this.media, bufferInfo.nextStart, playlistType, 0); if (nextbufferInfo !== null && bufferInfo.len + nextbufferInfo.len >= maxBufLen) { const sn = nextFragment.sn; if (this.loopSn !== sn) { this.log(`buffer full after gaps in "${playlistType}" playlist starting at sn: ${sn}`); this.loopSn = sn; } return null; } } } this.loopSn = void 0; return nextFragment; } get primaryPrefetch() { if (interstitialsEnabled(this.config)) { var _this$hls$interstitia; if ((_this$hls$interstitia = this.hls.interstitialsManager) == null || (_this$hls$interstitia = _this$hls$interstitia.playingItem) == null ? void 0 : _this$hls$interstitia.event) return true; } return false; } filterReplacedPrimary(frag, details) { if (!frag) return frag; if (interstitialsEnabled(this.config) && frag.type !== PlaylistLevelType.SUBTITLE) { const interstitials = this.hls.interstitialsManager; const bufferingItem = interstitials == null ? void 0 : interstitials.bufferingItem; if (bufferingItem) { const bufferingInterstitial = bufferingItem.event; if (bufferingInterstitial) { if (bufferingInterstitial.appendInPlace || Math.abs(frag.start - bufferingItem.start) > 1 || bufferingItem.start === 0) return null; } else { if (frag.end <= bufferingItem.start && (details == null ? void 0 : details.live) === false) return null; if (frag.start > bufferingItem.end && bufferingItem.nextEvent) { if (bufferingItem.nextEvent.appendInPlace || frag.start - bufferingItem.end > 1) return null; } } } const playerQueue = interstitials == null ? void 0 : interstitials.playerQueue; if (playerQueue) for (let i = playerQueue.length; i--;) { const interstitial = playerQueue[i].interstitial; if (interstitial.appendInPlace && frag.start >= interstitial.startTime && frag.end <= interstitial.resumeTime) return null; } } return frag; } mapToInitFragWhenRequired(frag) { if (frag != null && frag.initSegment && !frag.initSegment.data && !this.bitrateTest) return frag.initSegment; return frag; } getNextPart(partList, frag, targetBufferTime) { let nextPart = -1; let contiguous = false; let independentAttrOmitted = true; for (let i = 0, len = partList.length; i < len; i++) { const part = partList[i]; independentAttrOmitted = independentAttrOmitted && !part.independent; if (nextPart > -1 && targetBufferTime < part.start) break; const loaded = part.loaded; if (loaded) nextPart = -1; else if (contiguous || (part.independent || independentAttrOmitted) && part.fragment === frag) { if (part.fragment !== frag) this.warn(`Need buffer at ${targetBufferTime} but next unloaded part starts at ${part.start}`); nextPart = i; } contiguous = loaded; } return nextPart; } loadedEndOfParts(partList, targetBufferTime) { let part; for (let i = partList.length; i--;) { part = partList[i]; if (!part.loaded) return false; if (targetBufferTime > part.start) return true; } return false; } getInitialLiveFragment(levelDetails) { const fragments = levelDetails.fragments; const fragPrevious = this.fragPrevious; let frag = null; if (fragPrevious) { if (levelDetails.hasProgramDateTime) { frag = findFragmentByPDT(fragments, fragPrevious.endProgramDateTime, this.config.maxFragLookUpTolerance); if (frag) this.log(`Live playlist, switching playlist, load frag with same PDT: ${fragPrevious.programDateTime}`); } if (!frag) { const targetSN = fragPrevious.sn + 1; if (targetSN >= levelDetails.startSN && targetSN <= levelDetails.endSN) { const fragNext = fragments[targetSN - levelDetails.startSN]; if (fragPrevious.cc === fragNext.cc) { frag = fragNext; this.log(`Live playlist, switching playlist, load frag with next SN: ${frag.sn}`); } } if (!frag) { frag = findNearestWithCC(levelDetails, fragPrevious.cc, fragPrevious.end); if (frag) this.log(`Live playlist, switching playlist, load frag with same CC: ${frag.sn}`); } } } else { const liveStart = this.hls.liveSyncPosition; if (liveStart !== null) frag = this.getFragmentAtPosition(liveStart, this.bitrateTest ? levelDetails.fragmentEnd : levelDetails.edge, levelDetails); } return frag; } getFragmentAtPosition(bufferEnd, end, levelDetails) { const { config } = this; let { fragPrevious } = this; let { fragments, endSN } = levelDetails; const { fragmentHint } = levelDetails; const { maxFragLookUpTolerance } = config; const partList = levelDetails.partList; const loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint); if (loadingParts && !this.bitrateTest && partList[partList.length - 1].fragment.sn === fragmentHint.sn) { fragments = fragments.concat(fragmentHint); endSN = fragmentHint.sn; } let frag; if (bufferEnd < end) { var _this$media3; const lookupTolerance = bufferEnd < this.lastCurrentTime || bufferEnd > end - maxFragLookUpTolerance || (_this$media3 = this.media) != null && _this$media3.paused || !this.startFragRequested ? 0 : maxFragLookUpTolerance; frag = findFragmentByPTS(fragPrevious, fragments, bufferEnd, lookupTolerance); } else frag = fragments[fragments.length - 1]; if (frag) { const curSNIdx = frag.sn - levelDetails.startSN; const fragState = this.fragmentTracker.getState(frag); if (fragState === FragmentState.OK || fragState === FragmentState.PARTIAL && frag.gap) fragPrevious = frag; if (fragPrevious && frag.sn === fragPrevious.sn && (!loadingParts || partList[0].fragment.sn > frag.sn || !levelDetails.live)) { if (frag.level === fragPrevious.level) { const nextFrag = fragments[curSNIdx + 1]; if (frag.sn < endSN && this.fragmentTracker.getState(nextFrag) !== FragmentState.OK) frag = nextFrag; else frag = null; } } } return frag; } alignPlaylists(details, previousDetails, switchDetails) { const length = details.fragments.length; if (!length) { this.warn(`No fragments in live playlist`); return 0; } const slidingStart = details.fragmentStart; const firstLevelLoad = !previousDetails; const aligned = details.alignedSliding && isFiniteNumber(slidingStart); if (firstLevelLoad || !aligned && !slidingStart) { alignStream(switchDetails, details); const alignedSlidingStart = details.fragmentStart; this.log(`Live playlist sliding: ${alignedSlidingStart.toFixed(2)} start-sn: ${previousDetails ? previousDetails.startSN : "na"}->${details.startSN} fragments: ${length}`); return alignedSlidingStart; } return slidingStart; } waitForCdnTuneIn(details) { return details.live && details.canBlockReload && details.partTarget && details.tuneInGoal > Math.max(details.partHoldBack, details.partTarget * 3); } setStartPosition(details, sliding) { let startPosition = this.startPosition; if (startPosition < sliding) startPosition = -1; const timelineOffset = this.timelineOffset; if (startPosition === -1) { const offsetInMultivariantPlaylist = this.startTimeOffset !== null; const startTimeOffset = offsetInMultivariantPlaylist ? this.startTimeOffset : details.startTimeOffset; if (startTimeOffset !== null && isFiniteNumber(startTimeOffset)) { startPosition = sliding + startTimeOffset; if (startTimeOffset < 0) startPosition += details.edge; startPosition = Math.min(Math.max(sliding, startPosition), sliding + details.totalduration); this.log(`Setting startPosition to ${startPosition} for start time offset ${startTimeOffset} found in ${offsetInMultivariantPlaylist ? "multivariant" : "media"} playlist`); this.startPosition = startPosition; } else if (details.live) { startPosition = this.hls.liveSyncPosition || sliding; this.log(`Setting startPosition to -1 to start at live edge ${startPosition}`); this.startPosition = -1; } else { this.log(`setting startPosition to 0 by default`); this.startPosition = startPosition = 0; } this.lastCurrentTime = startPosition + timelineOffset; } this.nextLoadPosition = startPosition + timelineOffset; } getLoadPosition() { var _this$hls; const { media } = this; let pos = 0; if ((_this$hls = this.hls) != null && _this$hls.hasEnoughToStart && media) pos = media.currentTime; else if (this.nextLoadPosition >= 0) pos = this.nextLoadPosition; return pos; } handleFragLoadAborted(frag, part) { if (this.transmuxer && frag.type === this.playlistType && isMediaFragment(frag) && frag.stats.aborted) { this.log(`Fragment ${frag.sn}${part ? " part " + part.index : ""} of ${this.playlistLabel()} ${frag.level} was aborted`); this.resetFragmentLoading(frag); } } resetFragmentLoading(frag) { if (!this.fragCurrent || !this.fragContextChanged(frag) && this.state !== State.FRAG_LOADING_WAITING_RETRY) this.state = State.IDLE; } onFragmentOrKeyLoadError(filterType, data) { var _this$hls$latestLevel; if (data.chunkMeta && !data.frag) { const context = this.getCurrentContext(data.chunkMeta); if (context) data.frag = context.frag; } const frag = data.frag; if (!frag || frag.type !== filterType || !this.levels) return; if (this.fragContextChanged(frag)) { var _this$fragCurrent; this.warn(`Frag load error must match current frag to retry ${frag.url} > ${(_this$fragCurrent = this.fragCurrent) == null ? void 0 : _this$fragCurrent.url}`); return; } const gapTagEncountered = data.details === ErrorDetails.FRAG_GAP; if (gapTagEncountered) this.fragmentTracker.fragBuffered(frag, true); const errorAction = data.errorAction; if (!errorAction) { this.state = State.ERROR; return; } const { action, flags, retryCount = 0, retryConfig } = errorAction; const couldRetry = !!retryConfig; const retry = couldRetry && action === NetworkErrorAction.RetryRequest; const noAlternate = couldRetry && !errorAction.resolved && flags === ErrorActionFlags.MoveAllAlternatesMatchingHost; const live = (_this$hls$latestLevel = this.hls.latestLevelDetails) == null ? void 0 : _this$hls$latestLevel.live; if (!retry && noAlternate && isMediaFragment(frag) && !frag.endList && live && !isUnusableKeyError(data)) { this.resetFragmentErrors(filterType); this.treatAsGap(frag); errorAction.resolved = true; } else if ((retry || noAlternate) && retryCount < retryConfig.maxNumRetry) { var _data$response; const offlineStatus = offlineHttpStatus((_data$response = data.response) == null ? void 0 : _data$response.code); const delay = getRetryDelay(retryConfig, retryCount); this.resetStartWhenNotLoaded(); this.retryDate = self.performance.now() + delay; this.state = State.FRAG_LOADING_WAITING_RETRY; errorAction.resolved = true; if (offlineStatus) { this.log(`Waiting for connection (offline)`); this.retryDate = Infinity; data.reason = "offline"; return; } this.warn(`Fragment ${frag.sn} of ${filterType} ${frag.level} errored with ${data.details}, retrying loading ${retryCount + 1}/${retryConfig.maxNumRetry} in ${delay}ms`); } else if (retryConfig) { this.resetFragmentErrors(filterType); if (retryCount < retryConfig.maxNumRetry) { if (!gapTagEncountered && action !== NetworkErrorAction.RemoveAlternatePermanently) errorAction.resolved = true; } else { this.warn(`${data.details} reached or exceeded max retry (${retryCount})`); return; } } else if (action === NetworkErrorAction.SendAlternateToPenaltyBox) this.state = State.WAITING_LEVEL; else this.state = State.ERROR; this.tickImmediate(); } checkRetryDate() { const now = self.performance.now(); const retryDate = this.retryDate; const waitingForConnection = retryDate === Infinity; if (!retryDate || now >= retryDate || waitingForConnection && !offlineHttpStatus(0)) { if (waitingForConnection) this.log(`Connection restored (online)`); this.resetStartWhenNotLoaded(); this.state = State.IDLE; } } reduceLengthAndFlushBuffer(data) { if (this.state === State.PARSING || this.state === State.PARSED) { const frag = data.frag; const playlistType = data.parent; const bufferedInfo = this.getFwdBufferInfo(this.mediaBuffer, playlistType); const buffered = bufferedInfo && bufferedInfo.len > .5; if (buffered) this.reduceMaxBufferLength(bufferedInfo.len, (frag == null ? void 0 : frag.duration) || 10); const flushBuffer = !buffered; if (flushBuffer) this.warn(`Buffer full error while media.currentTime (${this.getLoadPosition()}) is not buffered, flush ${playlistType} buffer`); if (frag) { this.fragmentTracker.removeFragment(frag); this.nextLoadPosition = frag.start; } this.resetLoadingState(); return flushBuffer; } return false; } resetFragmentErrors(filterType) { if (filterType === PlaylistLevelType.AUDIO) this.fragCurrent = null; if (!this.hls.hasEnoughToStart) this.startFragRequested = false; if (this.state !== State.STOPPED) this.state = State.IDLE; } afterBufferFlushed(media, bufferType, playlistType) { if (!media) return; const bufferedTimeRanges = BufferHelper.getBuffered(media); this.fragmentTracker.detectEvictedFragments(bufferType, bufferedTimeRanges, playlistType); if (this.state === State.ENDED) this.resetLoadingState(); } resetLoadingState() { this.log("Reset loading state"); this.fragCurrent = null; this.fragPrevious = null; if (this.state !== State.STOPPED) this.state = State.IDLE; } resetStartWhenNotLoaded() { if (!this.hls.hasEnoughToStart) { this.startFragRequested = false; const level = this.levelLastLoaded; const details = level ? level.details : null; if (details != null && details.live) { this.log(`resetting startPosition for live start`); this.startPosition = -1; this.setStartPosition(details, details.fragmentStart); this.resetLoadingState(); } else this.nextLoadPosition = this.startPosition; } } resetWhenMissingContext(chunkMeta) { this.log(`Loading context changed while buffering sn ${chunkMeta.sn} of ${this.playlistLabel()} ${chunkMeta.level === -1 ? "" : chunkMeta.level}. This chunk will not be buffered.`); this.removeUnbufferedFrags(); this.resetStartWhenNotLoaded(); this.resetLoadingState(); } removeUnbufferedFrags(start = 0) { this.fragmentTracker.removeFragmentsInRange(start, Infinity, this.playlistType, false, true); } updateLevelTiming(frag, part, level, partial) { const details = level.details; if (!details) { this.warn("level.details undefined"); return; } if (!Object.keys(frag.elementaryStreams).reduce((result, type) => { const info = frag.elementaryStreams[type]; if (info) { const parsedDuration = info.endPTS - info.startPTS; if (parsedDuration <= 0) { this.warn(`Could not parse fragment ${frag.sn} ${type} duration reliably (${parsedDuration})`); return result || false; } const drift = partial ? 0 : updateFragPTSDTS(details, frag, info.startPTS, info.endPTS, info.startDTS, info.endDTS, this); this.hls.trigger(Events.LEVEL_PTS_UPDATED, { details, level, drift, type, frag, start: info.startPTS, end: info.endPTS }); return true; } return result; }, false)) { var _this$transmuxer; const mediaNotFound = ((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null; if (level.fragmentError === 0 || mediaNotFound && (level.fragmentError < 2 || frag.endList)) this.treatAsGap(frag, level); if (mediaNotFound) { const error = /* @__PURE__ */ new Error(`Found no media in fragment ${frag.sn} of ${this.playlistLabel()} ${frag.level} resetting transmuxer to fallback to playlist timing`); this.warn(error.message); this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, error, frag, reason: `Found no media in msn ${frag.sn} of ${this.playlistLabel()} "${level.url}"` }); if (!this.hls) return; this.resetTransmuxer(); } } this.state = State.PARSED; this.log(`Parsed ${frag.type} sn: ${frag.sn}${part ? " part: " + part.index : ""} of ${this.fragInfo(frag, false, part)})`); this.hls.trigger(Events.FRAG_PARSED, { frag, part }); } playlistLabel() { return this.playlistType === PlaylistLevelType.MAIN ? "level" : "track"; } fragInfo(frag, pts = true, part) { var _ref, _ref2; return `${this.playlistLabel()} ${frag.level} (${part ? "part" : "frag"}:[${((_ref = pts && !part ? frag.startPTS : (part || frag).start) != null ? _ref : NaN).toFixed(3)}-${((_ref2 = pts && !part ? frag.endPTS : (part || frag).end) != null ? _ref2 : NaN).toFixed(3)}]${part && frag.type === "main" ? "INDEPENDENT=" + (part.independent ? "YES" : "NO") : ""}`; } treatAsGap(frag, level) { if (level) level.fragmentError++; frag.gap = true; this.fragmentTracker.removeFragment(frag); this.fragmentTracker.fragBuffered(frag, true); } resetTransmuxer() { var _this$transmuxer2; (_this$transmuxer2 = this.transmuxer) == null || _this$transmuxer2.reset(); } recoverWorkerError(data) { if (data.event === "demuxerWorker") { this.fragmentTracker.removeAllFragments(); if (this.transmuxer) { this.transmuxer.destroy(); this.transmuxer = null; } this.resetStartWhenNotLoaded(); this.resetLoadingState(); } } set state(nextState) { const previousState = this._state; if (previousState !== nextState) { this._state = nextState; this.log(`${previousState}->${nextState}`); } } get state() { return this._state; } }; function interstitialsEnabled(config) { return !!config.interstitialsController && config.enableInterstitialPlayback !== false; } var ChunkCache = class { constructor() { this.chunks = []; this.dataLength = 0; } push(chunk) { this.chunks.push(chunk); this.dataLength += chunk.length; } flush() { const { chunks, dataLength } = this; let result; if (!chunks.length) return new Uint8Array(0); else if (chunks.length === 1) result = chunks[0]; else result = concatUint8Arrays(chunks, dataLength); this.reset(); return result; } reset() { this.chunks.length = 0; this.dataLength = 0; } }; function concatUint8Arrays(chunks, dataLength) { const result = new Uint8Array(dataLength); let offset = 0; for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; result.set(chunk, offset); offset += chunk.length; } return result; } var eventemitter3 = { exports: {} }; var hasRequiredEventemitter3; function requireEventemitter3() { if (hasRequiredEventemitter3) return eventemitter3.exports; hasRequiredEventemitter3 = 1; (function(module) { var has = Object.prototype.hasOwnProperty, prefix = "~"; /** * Constructor to create a storage for our `EE` objects. * An `Events` instance is a plain object whose properties are event names. * * @constructor * @private */ function Events() {} if (Object.create) { Events.prototype = Object.create(null); if (!new Events().__proto__) prefix = false; } /** * Representation of a single event listener. * * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} [once=false] Specify if the listener is a one-time listener. * @constructor * @private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Add a listener for a given event. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} once Specify if the listener is a one-time listener. * @returns {EventEmitter} * @private */ function addListener(emitter, event, fn, context, once) { if (typeof fn !== "function") throw new TypeError("The listener must be a function"); var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event; if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); else emitter._events[evt] = [emitter._events[evt], listener]; return emitter; } /** * Clear event by name. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} evt The Event name. * @private */ function clearEvent(emitter, evt) { if (--emitter._eventsCount === 0) emitter._events = new Events(); else delete emitter._events[evt]; } /** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. * * @constructor * @public */ function EventEmitter() { this._events = new Events(); this._eventsCount = 0; } /** * Return an array listing the events for which the emitter has registered * listeners. * * @returns {Array} * @public */ EventEmitter.prototype.eventNames = function eventNames() { var names = [], events, name; if (this._eventsCount === 0) return names; for (name in events = this._events) if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); if (Object.getOwnPropertySymbols) return names.concat(Object.getOwnPropertySymbols(events)); return names; }; /** * Return the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Array} The registered listeners. * @public */ EventEmitter.prototype.listeners = function listeners(event) { var evt = prefix ? prefix + event : event, handlers = this._events[evt]; if (!handlers) return []; if (handlers.fn) return [handlers.fn]; for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) ee[i] = handlers[i].fn; return ee; }; /** * Return the number of listeners listening to a given event. * * @param {(String|Symbol)} event The event name. * @returns {Number} The number of listeners. * @public */ EventEmitter.prototype.listenerCount = function listenerCount(event) { var evt = prefix ? prefix + event : event, listeners = this._events[evt]; if (!listeners) return 0; if (listeners.fn) return 1; return listeners.length; }; /** * Calls each of the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Boolean} `true` if the event had listeners, else `false`. * @public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return false; var listeners = this._events[evt], len = arguments.length, args, i; if (listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, void 0, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len - 1); i < len; i++) args[i - 1] = arguments[i]; listeners.fn.apply(listeners.context, args); } else { var length = listeners.length, j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; default: if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) args[j - 1] = arguments[j]; listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Add a listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.on = function on(event, fn, context) { return addListener(this, event, fn, context, false); }; /** * Add a one-time listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.once = function once(event, fn, context) { return addListener(this, event, fn, context, true); }; /** * Remove the listeners of a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn Only remove the listeners that match this function. * @param {*} context Only remove the listeners that have this context. * @param {Boolean} once Only remove one-time listeners. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return this; if (!fn) { clearEvent(this, evt); return this; } var listeners = this._events[evt]; if (listeners.fn) { if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) clearEvent(this, evt); } else { for (var i = 0, events = [], length = listeners.length; i < length; i++) if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) events.push(listeners[i]); if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; else clearEvent(this, evt); } return this; }; /** * Remove all listeners, or those of the specified event. * * @param {(String|Symbol)} [event] The event name. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { var evt; if (event) { evt = prefix ? prefix + event : event; if (this._events[evt]) clearEvent(this, evt); } else { this._events = new Events(); this._eventsCount = 0; } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; EventEmitter.prefixed = prefix; EventEmitter.EventEmitter = EventEmitter; module.exports = EventEmitter; })(eventemitter3); return eventemitter3.exports; } var EventEmitter = /*@__PURE__*/ getDefaultExportFromCjs(requireEventemitter3()); var version = "1.6.16"; var workerStore = {}; function hasUMDWorker() { return typeof __HLS_WORKER_BUNDLE__ === "function"; } function injectWorker() { const workerContext = workerStore[version]; if (workerContext) { workerContext.clientCount++; return workerContext; } const blob = new self.Blob([`var exports={};var module={exports:exports};function define(f){f()};define.amd=true;(${__HLS_WORKER_BUNDLE__.toString()})(true);`], { type: "text/javascript" }); const objectURL = self.URL.createObjectURL(blob); const result = { worker: new self.Worker(objectURL), objectURL, clientCount: 1 }; workerStore[version] = result; return result; } function loadWorker(path) { const workerContext = workerStore[path]; if (workerContext) { workerContext.clientCount++; return workerContext; } const scriptURL = new self.URL(path, self.location.href).href; const result = { worker: new self.Worker(scriptURL), scriptURL, clientCount: 1 }; workerStore[path] = result; return result; } function removeWorkerFromStore(path) { const workerContext = workerStore[path || version]; if (workerContext) { if (workerContext.clientCount-- === 1) { const { worker, objectURL } = workerContext; delete workerStore[path || version]; if (objectURL) self.URL.revokeObjectURL(objectURL); worker.terminate(); } } } /** * Returns true if an ID3 footer can be found at offset in data * * @param data - The data to search in * @param offset - The offset at which to start searching * * @returns `true` if an ID3 footer is found * * @internal * * @group ID3 */ function isId3Footer(data, offset) { if (offset + 10 <= data.length) { if (data[offset] === 51 && data[offset + 1] === 68 && data[offset + 2] === 73) { if (data[offset + 3] < 255 && data[offset + 4] < 255) { if (data[offset + 6] < 128 && data[offset + 7] < 128 && data[offset + 8] < 128 && data[offset + 9] < 128) return true; } } } return false; } /** * Returns true if an ID3 header can be found at offset in data * * @param data - The data to search in * @param offset - The offset at which to start searching * * @returns `true` if an ID3 header is found * * @internal * * @group ID3 */ function isId3Header(data, offset) { if (offset + 10 <= data.length) { if (data[offset] === 73 && data[offset + 1] === 68 && data[offset + 2] === 51) { if (data[offset + 3] < 255 && data[offset + 4] < 255) { if (data[offset + 6] < 128 && data[offset + 7] < 128 && data[offset + 8] < 128 && data[offset + 9] < 128) return true; } } } return false; } /** * Read ID3 size * * @param data - The data to read from * @param offset - The offset at which to start reading * * @returns The size * * @internal * * @group ID3 */ function readId3Size(data, offset) { let size = 0; size = (data[offset] & 127) << 21; size |= (data[offset + 1] & 127) << 14; size |= (data[offset + 2] & 127) << 7; size |= data[offset + 3] & 127; return size; } /** * Returns any adjacent ID3 tags found in data starting at offset, as one block of data * * @param data - The data to search in * @param offset - The offset at which to start searching * * @returns The block of data containing any ID3 tags found * or `undefined` if no header is found at the starting offset * * @internal * * @group ID3 */ function getId3Data(data, offset) { const front = offset; let length = 0; while (isId3Header(data, offset)) { length += 10; const size = readId3Size(data, offset + 6); length += size; if (isId3Footer(data, offset + 10)) length += 10; offset += length; } if (length > 0) return data.subarray(front, front + length); } function getAudioConfig(observer, data, offset, manifestCodec) { const adtsSamplingRates = [ 96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350 ]; const byte2 = data[offset + 2]; const adtsSamplingIndex = byte2 >> 2 & 15; if (adtsSamplingIndex > 12) { const error = /* @__PURE__ */ new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`); observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, error, reason: error.message }); return; } const adtsObjectType = (byte2 >> 6 & 3) + 1; const channelCount = data[offset + 3] >> 6 & 3 | (byte2 & 1) << 2; const codec = "mp4a.40." + adtsObjectType; const samplerate = adtsSamplingRates[adtsSamplingIndex]; let aacSampleIndex = adtsSamplingIndex; if (adtsObjectType === 5 || adtsObjectType === 29) aacSampleIndex -= 3; const config = [adtsObjectType << 3 | (aacSampleIndex & 14) >> 1, (aacSampleIndex & 1) << 7 | channelCount << 3]; logger.log(`manifest codec:${manifestCodec}, parsed codec:${codec}, channels:${channelCount}, rate:${samplerate} (ADTS object type:${adtsObjectType} sampling index:${adtsSamplingIndex})`); return { config, samplerate, channelCount, codec, parsedCodec: codec, manifestCodec }; } function isHeaderPattern$1(data, offset) { return data[offset] === 255 && (data[offset + 1] & 246) === 240; } function getHeaderLength(data, offset) { return data[offset + 1] & 1 ? 7 : 9; } function getFullFrameLength(data, offset) { return (data[offset + 3] & 3) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 224) >>> 5; } function canGetFrameLength(data, offset) { return offset + 5 < data.length; } function isHeader$1(data, offset) { return offset + 1 < data.length && isHeaderPattern$1(data, offset); } function canParse$1(data, offset) { return canGetFrameLength(data, offset) && isHeaderPattern$1(data, offset) && getFullFrameLength(data, offset) <= data.length - offset; } function probe$1(data, offset) { if (isHeader$1(data, offset)) { const headerLength = getHeaderLength(data, offset); if (offset + headerLength >= data.length) return false; const frameLength = getFullFrameLength(data, offset); if (frameLength <= headerLength) return false; const newOffset = offset + frameLength; return newOffset === data.length || isHeader$1(data, newOffset); } return false; } function initTrackConfig(track, observer, data, offset, audioCodec) { if (!track.samplerate) { const config = getAudioConfig(observer, data, offset, audioCodec); if (!config) return; _extends(track, config); } } function getFrameDuration(samplerate) { return 1024 * 9e4 / samplerate; } function parseFrameHeader(data, offset) { const headerLength = getHeaderLength(data, offset); if (offset + headerLength <= data.length) { const frameLength = getFullFrameLength(data, offset) - headerLength; if (frameLength > 0) return { headerLength, frameLength }; } } function appendFrame$2(track, data, offset, pts, frameIndex) { const stamp = pts + frameIndex * getFrameDuration(track.samplerate); const header = parseFrameHeader(data, offset); let unit; if (header) { const { frameLength, headerLength } = header; const _length = headerLength + frameLength; const missing = Math.max(0, offset + _length - data.length); if (missing) { unit = new Uint8Array(_length - headerLength); unit.set(data.subarray(offset + headerLength, data.length), 0); } else unit = data.subarray(offset + headerLength, offset + _length); const _sample = { unit, pts: stamp }; if (!missing) track.samples.push(_sample); return { sample: _sample, length: _length, missing }; } const length = data.length - offset; unit = new Uint8Array(length); unit.set(data.subarray(offset, data.length), 0); return { sample: { unit, pts: stamp }, length, missing: -1 }; } /** * Checks if the given data contains an ID3 tag. * * @param data - The data to check * @param offset - The offset at which to start checking * * @returns `true` if an ID3 tag is found * * @group ID3 * * @beta */ function canParseId3(data, offset) { return isId3Header(data, offset) && readId3Size(data, offset + 6) + 10 <= data.length - offset; } function toArrayBuffer(view) { if (view instanceof ArrayBuffer) return view; else { if (view.byteOffset == 0 && view.byteLength == view.buffer.byteLength) return view.buffer; return new Uint8Array(view).buffer; } } function toUint8(data, offset = 0, length = Infinity) { return view(data, offset, length, Uint8Array); } function view(data, offset, length, Type) { const buffer = unsafeGetArrayBuffer(data); let bytesPerElement = 1; if ("BYTES_PER_ELEMENT" in Type) bytesPerElement = Type.BYTES_PER_ELEMENT; const dataOffset = isArrayBufferView(data) ? data.byteOffset : 0; const dataEnd = (dataOffset + data.byteLength) / bytesPerElement; const rawStart = (dataOffset + offset) / bytesPerElement; const start = Math.floor(Math.max(0, Math.min(rawStart, dataEnd))); return new Type(buffer, start, Math.floor(Math.min(start + Math.max(length, 0), dataEnd)) - start); } function unsafeGetArrayBuffer(view) { if (view instanceof ArrayBuffer) return view; else return view.buffer; } function isArrayBufferView(obj) { return obj && obj.buffer instanceof ArrayBuffer && obj.byteLength !== void 0 && obj.byteOffset !== void 0; } function decodeId3ImageFrame(frame) { const metadataFrame = { key: frame.type, description: "", data: "", mimeType: null, pictureType: null }; const utf8Encoding = 3; if (frame.size < 2) return; if (frame.data[0] !== utf8Encoding) { console.log("Ignore frame with unrecognized character encoding"); return; } const mimeTypeEndIndex = frame.data.subarray(1).indexOf(0); if (mimeTypeEndIndex === -1) return; const mimeType = utf8ArrayToStr(toUint8(frame.data, 1, mimeTypeEndIndex)); const pictureType = frame.data[2 + mimeTypeEndIndex]; const descriptionEndIndex = frame.data.subarray(3 + mimeTypeEndIndex).indexOf(0); if (descriptionEndIndex === -1) return; const description = utf8ArrayToStr(toUint8(frame.data, 3 + mimeTypeEndIndex, descriptionEndIndex)); let data; if (mimeType === "-->") data = utf8ArrayToStr(toUint8(frame.data, 4 + mimeTypeEndIndex + descriptionEndIndex)); else data = toArrayBuffer(frame.data.subarray(4 + mimeTypeEndIndex + descriptionEndIndex)); metadataFrame.mimeType = mimeType; metadataFrame.pictureType = pictureType; metadataFrame.description = description; metadataFrame.data = data; return metadataFrame; } /** * Decode an ID3 PRIV frame. * * @param frame - the ID3 PRIV frame * * @returns The decoded ID3 PRIV frame * * @internal * * @group ID3 */ function decodeId3PrivFrame(frame) { if (frame.size < 2) return; const owner = utf8ArrayToStr(frame.data, true); const privateData = new Uint8Array(frame.data.subarray(owner.length + 1)); return { key: frame.type, info: owner, data: privateData.buffer }; } /** * Decodes an ID3 text frame * * @param frame - the ID3 text frame * * @returns The decoded ID3 text frame * * @internal * * @group ID3 */ function decodeId3TextFrame(frame) { if (frame.size < 2) return; if (frame.type === "TXXX") { let index = 1; const description = utf8ArrayToStr(frame.data.subarray(index), true); index += description.length + 1; const value = utf8ArrayToStr(frame.data.subarray(index)); return { key: frame.type, info: description, data: value }; } const text = utf8ArrayToStr(frame.data.subarray(1)); return { key: frame.type, info: "", data: text }; } /** * Decode a URL frame * * @param frame - the ID3 URL frame * * @returns The decoded ID3 URL frame * * @internal * * @group ID3 */ function decodeId3UrlFrame(frame) { if (frame.type === "WXXX") { if (frame.size < 2) return; let index = 1; const description = utf8ArrayToStr(frame.data.subarray(index), true); index += description.length + 1; const value = utf8ArrayToStr(frame.data.subarray(index)); return { key: frame.type, info: description, data: value }; } const url = utf8ArrayToStr(frame.data); return { key: frame.type, info: "", data: url }; } /** * Decode an ID3 frame. * * @param frame - the ID3 frame * * @returns The decoded ID3 frame * * @internal * * @group ID3 */ function decodeId3Frame(frame) { if (frame.type === "PRIV") return decodeId3PrivFrame(frame); else if (frame.type[0] === "W") return decodeId3UrlFrame(frame); else if (frame.type === "APIC") return decodeId3ImageFrame(frame); return decodeId3TextFrame(frame); } /** * Returns the data of an ID3 frame. * * @param data - The data to read from * * @returns The data of the ID3 frame * * @internal * * @group ID3 */ function getId3FrameData(data) { const type = String.fromCharCode(data[0], data[1], data[2], data[3]); const size = readId3Size(data, 4); const offset = 10; return { type, size, data: data.subarray(offset, offset + size) }; } var HEADER_FOOTER_SIZE = 10; var FRAME_SIZE = 10; /** * Returns an array of ID3 frames found in all the ID3 tags in the id3Data * * @param id3Data - The ID3 data containing one or more ID3 tags * * @returns Array of ID3 frame objects * * @group ID3 * * @beta */ function getId3Frames(id3Data) { let offset = 0; const frames = []; while (isId3Header(id3Data, offset)) { const size = readId3Size(id3Data, offset + 6); if (id3Data[offset + 5] >> 6 & 1) offset += HEADER_FOOTER_SIZE; offset += HEADER_FOOTER_SIZE; const end = offset + size; while (offset + FRAME_SIZE < end) { const frameData = getId3FrameData(id3Data.subarray(offset)); const frame = decodeId3Frame(frameData); if (frame) frames.push(frame); offset += frameData.size + HEADER_FOOTER_SIZE; } if (isId3Footer(id3Data, offset)) offset += HEADER_FOOTER_SIZE; } return frames; } /** * Returns true if the ID3 frame is an Elementary Stream timestamp frame * * @param frame - the ID3 frame * * @returns `true` if the ID3 frame is an Elementary Stream timestamp frame * * @internal * * @group ID3 */ function isId3TimestampFrame(frame) { return frame && frame.key === "PRIV" && frame.info === "com.apple.streaming.transportStreamTimestamp"; } /** * Read a 33 bit timestamp from an ID3 frame. * * @param timeStampFrame - the ID3 frame * * @returns The timestamp * * @internal * * @group ID3 */ function readId3Timestamp(timeStampFrame) { if (timeStampFrame.data.byteLength === 8) { const data = new Uint8Array(timeStampFrame.data); const pts33Bit = data[3] & 1; let timestamp = (data[4] << 23) + (data[5] << 15) + (data[6] << 7) + data[7]; timestamp /= 45; if (pts33Bit) timestamp += 47721858.84; return Math.round(timestamp); } } /** * Searches for the Elementary Stream timestamp found in the ID3 data chunk * * @param data - Block of data containing one or more ID3 tags * * @returns The timestamp * * @group ID3 * * @beta */ function getId3Timestamp(data) { const frames = getId3Frames(data); for (let i = 0; i < frames.length; i++) { const frame = frames[i]; if (isId3TimestampFrame(frame)) return readId3Timestamp(frame); } } var MetadataSchema = /*#__PURE__*/ function(MetadataSchema) { MetadataSchema["audioId3"] = "org.id3"; MetadataSchema["dateRange"] = "com.apple.quicktime.HLS"; MetadataSchema["emsg"] = "https://aomedia.org/emsg/ID3"; MetadataSchema["misbklv"] = "urn:misb:KLV:bin:1910.1"; return MetadataSchema; }({}); function dummyTrack(type = "", inputTimeScale = 9e4) { return { type, id: -1, pid: -1, inputTimeScale, sequenceNumber: -1, samples: [], dropped: 0 }; } var BaseAudioDemuxer = class { constructor() { this._audioTrack = void 0; this._id3Track = void 0; this.frameIndex = 0; this.cachedData = null; this.basePTS = null; this.initPTS = null; this.lastPTS = null; } resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { this._id3Track = { type: "id3", id: 3, pid: -1, inputTimeScale: 9e4, sequenceNumber: 0, samples: [], dropped: 0 }; } resetTimeStamp(deaultTimestamp) { this.initPTS = deaultTimestamp; this.resetContiguity(); } resetContiguity() { this.basePTS = null; this.lastPTS = null; this.frameIndex = 0; } canParse(data, offset) { return false; } appendFrame(track, data, offset) {} demux(data, timeOffset) { if (this.cachedData) { data = appendUint8Array(this.cachedData, data); this.cachedData = null; } let id3Data = getId3Data(data, 0); let offset = id3Data ? id3Data.length : 0; let lastDataIndex; const track = this._audioTrack; const id3Track = this._id3Track; const timestamp = id3Data ? getId3Timestamp(id3Data) : void 0; const length = data.length; if (this.basePTS === null || this.frameIndex === 0 && isFiniteNumber(timestamp)) { this.basePTS = initPTSFn(timestamp, timeOffset, this.initPTS); this.lastPTS = this.basePTS; } if (this.lastPTS === null) this.lastPTS = this.basePTS; if (id3Data && id3Data.length > 0) id3Track.samples.push({ pts: this.lastPTS, dts: this.lastPTS, data: id3Data, type: MetadataSchema.audioId3, duration: Number.POSITIVE_INFINITY }); while (offset < length) { if (this.canParse(data, offset)) { const frame = this.appendFrame(track, data, offset); if (frame) { this.frameIndex++; this.lastPTS = frame.sample.pts; offset += frame.length; lastDataIndex = offset; } else offset = length; } else if (canParseId3(data, offset)) { id3Data = getId3Data(data, offset); id3Track.samples.push({ pts: this.lastPTS, dts: this.lastPTS, data: id3Data, type: MetadataSchema.audioId3, duration: Number.POSITIVE_INFINITY }); offset += id3Data.length; lastDataIndex = offset; } else offset++; if (offset === length && lastDataIndex !== length) { const partialData = data.slice(lastDataIndex); if (this.cachedData) this.cachedData = appendUint8Array(this.cachedData, partialData); else this.cachedData = partialData; } } return { audioTrack: track, videoTrack: dummyTrack(), id3Track, textTrack: dummyTrack() }; } demuxSampleAes(data, keyData, timeOffset) { return Promise.reject(/* @__PURE__ */ new Error(`[${this}] This demuxer does not support Sample-AES decryption`)); } flush(timeOffset) { const cachedData = this.cachedData; if (cachedData) { this.cachedData = null; this.demux(cachedData, 0); } return { audioTrack: this._audioTrack, videoTrack: dummyTrack(), id3Track: this._id3Track, textTrack: dummyTrack() }; } destroy() { this.cachedData = null; this._audioTrack = this._id3Track = void 0; } }; /** * Initialize PTS *

* use timestamp unless it is undefined, NaN or Infinity *

*/ var initPTSFn = (timestamp, timeOffset, initPTS) => { if (isFiniteNumber(timestamp)) return timestamp * 90; const init90kHz = initPTS ? initPTS.baseTime * 9e4 / initPTS.timescale : 0; return timeOffset * 9e4 + init90kHz; }; /** * MPEG parser helper */ var chromeVersion$1 = null; var BitratesMap = [ 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ]; var SamplingRateMap = [ 44100, 48e3, 32e3, 22050, 24e3, 16e3, 11025, 12e3, 8e3 ]; var SamplesCoefficients = [ [ 0, 72, 144, 12 ], [ 0, 0, 0, 0 ], [ 0, 72, 144, 12 ], [ 0, 144, 144, 12 ] ]; var BytesInSlot = [ 0, 1, 1, 4 ]; function appendFrame$1(track, data, offset, pts, frameIndex) { if (offset + 24 > data.length) return; const header = parseHeader(data, offset); if (header && offset + header.frameLength <= data.length) { const stamp = pts + frameIndex * (header.samplesPerFrame * 9e4 / header.sampleRate); const sample = { unit: data.subarray(offset, offset + header.frameLength), pts: stamp, dts: stamp }; track.config = []; track.channelCount = header.channelCount; track.samplerate = header.sampleRate; track.samples.push(sample); return { sample, length: header.frameLength, missing: 0 }; } } function parseHeader(data, offset) { const mpegVersion = data[offset + 1] >> 3 & 3; const mpegLayer = data[offset + 1] >> 1 & 3; const bitRateIndex = data[offset + 2] >> 4 & 15; const sampleRateIndex = data[offset + 2] >> 2 & 3; if (mpegVersion !== 1 && bitRateIndex !== 0 && bitRateIndex !== 15 && sampleRateIndex !== 3) { const paddingBit = data[offset + 2] >> 1 & 1; const channelMode = data[offset + 3] >> 6; const bitRate = BitratesMap[(mpegVersion === 3 ? 3 - mpegLayer : mpegLayer === 3 ? 3 : 4) * 14 + bitRateIndex - 1] * 1e3; const sampleRate = SamplingRateMap[(mpegVersion === 3 ? 0 : mpegVersion === 2 ? 1 : 2) * 3 + sampleRateIndex]; const channelCount = channelMode === 3 ? 1 : 2; const sampleCoefficient = SamplesCoefficients[mpegVersion][mpegLayer]; const bytesInSlot = BytesInSlot[mpegLayer]; const samplesPerFrame = sampleCoefficient * 8 * bytesInSlot; const frameLength = Math.floor(sampleCoefficient * bitRate / sampleRate + paddingBit) * bytesInSlot; if (chromeVersion$1 === null) { const result = (navigator.userAgent || "").match(/Chrome\/(\d+)/i); chromeVersion$1 = result ? parseInt(result[1]) : 0; } if (!!chromeVersion$1 && chromeVersion$1 <= 87 && mpegLayer === 2 && bitRate >= 224e3 && channelMode === 0) data[offset + 3] = data[offset + 3] | 128; return { sampleRate, channelCount, frameLength, samplesPerFrame }; } } function isHeaderPattern(data, offset) { return data[offset] === 255 && (data[offset + 1] & 224) === 224 && (data[offset + 1] & 6) !== 0; } function isHeader(data, offset) { return offset + 1 < data.length && isHeaderPattern(data, offset); } function canParse(data, offset) { return isHeaderPattern(data, offset) && 4 <= data.length - offset; } function probe(data, offset) { if (offset + 1 < data.length && isHeaderPattern(data, offset)) { const headerLength = 4; const header = parseHeader(data, offset); let frameLength = headerLength; if (header != null && header.frameLength) frameLength = header.frameLength; const newOffset = offset + frameLength; return newOffset === data.length || isHeader(data, newOffset); } return false; } /** * AAC demuxer */ var AACDemuxer = class extends BaseAudioDemuxer { constructor(observer, config) { super(); this.observer = void 0; this.config = void 0; this.observer = observer; this.config = config; } resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { super.resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration); this._audioTrack = { container: "audio/adts", type: "audio", id: 2, pid: -1, sequenceNumber: 0, segmentCodec: "aac", samples: [], manifestCodec: audioCodec, duration: trackDuration, inputTimeScale: 9e4, dropped: 0 }; } static probe(data, logger) { if (!data) return false; const id3Data = getId3Data(data, 0); let offset = (id3Data == null ? void 0 : id3Data.length) || 0; if (probe(data, offset)) return false; for (let length = data.length; offset < length; offset++) if (probe$1(data, offset)) { logger.log("ADTS sync word found !"); return true; } return false; } canParse(data, offset) { return canParse$1(data, offset); } appendFrame(track, data, offset) { initTrackConfig(track, this.observer, data, offset, track.manifestCodec); const frame = appendFrame$2(track, data, offset, this.basePTS, this.frameIndex); if (frame && frame.missing === 0) return frame; } }; var getAudioBSID = (data, offset) => { let bsid = 0; let numBits = 5; offset += numBits; const temp = new Uint32Array(1); const mask = new Uint32Array(1); const byte = new Uint8Array(1); while (numBits > 0) { byte[0] = data[offset]; const bits = Math.min(numBits, 8); const shift = 8 - bits; mask[0] = 4278190080 >>> 24 + shift << shift; temp[0] = (byte[0] & mask[0]) >> shift; bsid = !bsid ? temp[0] : bsid << bits | temp[0]; offset += 1; numBits -= bits; } return bsid; }; var AC3Demuxer = class extends BaseAudioDemuxer { constructor(observer) { super(); this.observer = void 0; this.observer = observer; } resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { super.resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration); this._audioTrack = { container: "audio/ac-3", type: "audio", id: 2, pid: -1, sequenceNumber: 0, segmentCodec: "ac3", samples: [], manifestCodec: audioCodec, duration: trackDuration, inputTimeScale: 9e4, dropped: 0 }; } canParse(data, offset) { return offset + 64 < data.length; } appendFrame(track, data, offset) { const frameLength = appendFrame(track, data, offset, this.basePTS, this.frameIndex); if (frameLength !== -1) return { sample: track.samples[track.samples.length - 1], length: frameLength, missing: 0 }; } static probe(data) { if (!data) return false; const id3Data = getId3Data(data, 0); if (!id3Data) return false; const offset = id3Data.length; if (data[offset] === 11 && data[offset + 1] === 119 && getId3Timestamp(id3Data) !== void 0 && getAudioBSID(data, offset) < 16) return true; return false; } }; function appendFrame(track, data, start, pts, frameIndex) { if (start + 8 > data.length) return -1; if (data[start] !== 11 || data[start + 1] !== 119) return -1; const samplingRateCode = data[start + 4] >> 6; if (samplingRateCode >= 3) return -1; const sampleRate = [ 48e3, 44100, 32e3 ][samplingRateCode]; const frameSizeCode = data[start + 4] & 63; const frameLength = [ 64, 69, 96, 64, 70, 96, 80, 87, 120, 80, 88, 120, 96, 104, 144, 96, 105, 144, 112, 121, 168, 112, 122, 168, 128, 139, 192, 128, 140, 192, 160, 174, 240, 160, 175, 240, 192, 208, 288, 192, 209, 288, 224, 243, 336, 224, 244, 336, 256, 278, 384, 256, 279, 384, 320, 348, 480, 320, 349, 480, 384, 417, 576, 384, 418, 576, 448, 487, 672, 448, 488, 672, 512, 557, 768, 512, 558, 768, 640, 696, 960, 640, 697, 960, 768, 835, 1152, 768, 836, 1152, 896, 975, 1344, 896, 976, 1344, 1024, 1114, 1536, 1024, 1115, 1536, 1152, 1253, 1728, 1152, 1254, 1728, 1280, 1393, 1920, 1280, 1394, 1920 ][frameSizeCode * 3 + samplingRateCode] * 2; if (start + frameLength > data.length) return -1; const channelMode = data[start + 6] >> 5; let skipCount = 0; if (channelMode === 2) skipCount += 2; else { if (channelMode & 1 && channelMode !== 1) skipCount += 2; if (channelMode & 4) skipCount += 2; } const lfeon = (data[start + 6] << 8 | data[start + 7]) >> 12 - skipCount & 1; const channelCount = [ 2, 1, 2, 3, 3, 4, 4, 5 ][channelMode] + lfeon; const bsid = data[start + 5] >> 3; const bsmod = data[start + 5] & 7; const config = new Uint8Array([ samplingRateCode << 6 | bsid << 1 | bsmod >> 2, (bsmod & 3) << 6 | channelMode << 3 | lfeon << 2 | frameSizeCode >> 4, frameSizeCode << 4 & 224 ]); const stamp = pts + frameIndex * (1536 / sampleRate * 9e4); const unit = data.subarray(start, start + frameLength); track.config = config; track.channelCount = channelCount; track.samplerate = sampleRate; track.samples.push({ unit, pts: stamp }); return frameLength; } /** * MP3 demuxer */ var MP3Demuxer = class extends BaseAudioDemuxer { resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { super.resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration); this._audioTrack = { container: "audio/mpeg", type: "audio", id: 2, pid: -1, sequenceNumber: 0, segmentCodec: "mp3", samples: [], manifestCodec: audioCodec, duration: trackDuration, inputTimeScale: 9e4, dropped: 0 }; } static probe(data) { if (!data) return false; const id3Data = getId3Data(data, 0); let offset = (id3Data == null ? void 0 : id3Data.length) || 0; if (id3Data && data[offset] === 11 && data[offset + 1] === 119 && getId3Timestamp(id3Data) !== void 0 && getAudioBSID(data, offset) <= 16) return false; for (let length = data.length; offset < length; offset++) if (probe(data, offset)) { logger.log("MPEG Audio sync word found !"); return true; } return false; } canParse(data, offset) { return canParse(data, offset); } appendFrame(track, data, offset) { if (this.basePTS === null) return; return appendFrame$1(track, data, offset, this.basePTS, this.frameIndex); } }; var emsgSchemePattern = /\/emsg[-/]ID3/i; var MP4Demuxer = class { constructor(observer, config) { this.remainderData = null; this.timeOffset = 0; this.config = void 0; this.videoTrack = void 0; this.audioTrack = void 0; this.id3Track = void 0; this.txtTrack = void 0; this.config = config; } resetTimeStamp() {} resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { const videoTrack = this.videoTrack = dummyTrack("video", 1); const audioTrack = this.audioTrack = dummyTrack("audio", 1); const captionTrack = this.txtTrack = dummyTrack("text", 1); this.id3Track = dummyTrack("id3", 1); this.timeOffset = 0; if (!(initSegment != null && initSegment.byteLength)) return; const initData = parseInitSegment(initSegment); if (initData.video) { const { id, timescale, codec, supplemental } = initData.video; videoTrack.id = id; videoTrack.timescale = captionTrack.timescale = timescale; videoTrack.codec = codec; videoTrack.supplemental = supplemental; } if (initData.audio) { const { id, timescale, codec } = initData.audio; audioTrack.id = id; audioTrack.timescale = timescale; audioTrack.codec = codec; } captionTrack.id = RemuxerTrackIdConfig.text; videoTrack.sampleDuration = 0; videoTrack.duration = audioTrack.duration = trackDuration; } resetContiguity() { this.remainderData = null; } static probe(data) { return hasMoofData(data); } demux(data, timeOffset) { this.timeOffset = timeOffset; let videoSamples = data; const videoTrack = this.videoTrack; const textTrack = this.txtTrack; if (this.config.progressive) { if (this.remainderData) videoSamples = appendUint8Array(this.remainderData, data); const segmentedData = segmentValidRange(videoSamples); this.remainderData = segmentedData.remainder; videoTrack.samples = segmentedData.valid || new Uint8Array(); } else videoTrack.samples = videoSamples; const id3Track = this.extractID3Track(videoTrack, timeOffset); textTrack.samples = parseSamples(timeOffset, videoTrack); return { videoTrack, audioTrack: this.audioTrack, id3Track, textTrack: this.txtTrack }; } flush() { const timeOffset = this.timeOffset; const videoTrack = this.videoTrack; const textTrack = this.txtTrack; videoTrack.samples = this.remainderData || new Uint8Array(); this.remainderData = null; const id3Track = this.extractID3Track(videoTrack, this.timeOffset); textTrack.samples = parseSamples(timeOffset, videoTrack); return { videoTrack, audioTrack: dummyTrack(), id3Track, textTrack: dummyTrack() }; } extractID3Track(videoTrack, timeOffset) { const id3Track = this.id3Track; if (videoTrack.samples.length) { const emsgs = findBox(videoTrack.samples, ["emsg"]); if (emsgs) emsgs.forEach((data) => { const emsgInfo = parseEmsg(data); if (emsgSchemePattern.test(emsgInfo.schemeIdUri)) { const pts = getEmsgStartTime(emsgInfo, timeOffset); let duration = emsgInfo.eventDuration === 4294967295 ? Number.POSITIVE_INFINITY : emsgInfo.eventDuration / emsgInfo.timeScale; if (duration <= .001) duration = Number.POSITIVE_INFINITY; const payload = emsgInfo.payload; id3Track.samples.push({ data: payload, len: payload.byteLength, dts: pts, pts, type: MetadataSchema.emsg, duration }); } else if (this.config.enableEmsgKLVMetadata && emsgInfo.schemeIdUri.startsWith("urn:misb:KLV:bin:1910.1")) { const pts = getEmsgStartTime(emsgInfo, timeOffset); id3Track.samples.push({ data: emsgInfo.payload, len: emsgInfo.payload.byteLength, dts: pts, pts, type: MetadataSchema.misbklv, duration: Number.POSITIVE_INFINITY }); } }); } return id3Track; } demuxSampleAes(data, keyData, timeOffset) { return Promise.reject(/* @__PURE__ */ new Error("The MP4 demuxer does not support SAMPLE-AES decryption")); } destroy() { this.config = null; this.remainderData = null; this.videoTrack = this.audioTrack = this.id3Track = this.txtTrack = void 0; } }; function getEmsgStartTime(emsgInfo, timeOffset) { return isFiniteNumber(emsgInfo.presentationTime) ? emsgInfo.presentationTime / emsgInfo.timeScale : timeOffset + emsgInfo.presentationTimeDelta / emsgInfo.timeScale; } /** * SAMPLE-AES decrypter */ var SampleAesDecrypter = class { constructor(observer, config, keyData) { this.keyData = void 0; this.decrypter = void 0; this.keyData = keyData; this.decrypter = new Decrypter(config, { removePKCS7Padding: false }); } decryptBuffer(encryptedData) { return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc); } decryptAacSample(samples, sampleIndex, callback) { const curUnit = samples[sampleIndex].unit; if (curUnit.length <= 16) return; const encryptedData = curUnit.subarray(16, curUnit.length - curUnit.length % 16); const encryptedBuffer = encryptedData.buffer.slice(encryptedData.byteOffset, encryptedData.byteOffset + encryptedData.length); this.decryptBuffer(encryptedBuffer).then((decryptedBuffer) => { const decryptedData = new Uint8Array(decryptedBuffer); curUnit.set(decryptedData, 16); if (!this.decrypter.isSync()) this.decryptAacSamples(samples, sampleIndex + 1, callback); }).catch(callback); } decryptAacSamples(samples, sampleIndex, callback) { for (;; sampleIndex++) { if (sampleIndex >= samples.length) { callback(); return; } if (samples[sampleIndex].unit.length < 32) continue; this.decryptAacSample(samples, sampleIndex, callback); if (!this.decrypter.isSync()) return; } } getAvcEncryptedData(decodedData) { const encryptedDataLen = Math.floor((decodedData.length - 48) / 160) * 16 + 16; const encryptedData = new Int8Array(encryptedDataLen); let outputPos = 0; for (let inputPos = 32; inputPos < decodedData.length - 16; inputPos += 160, outputPos += 16) encryptedData.set(decodedData.subarray(inputPos, inputPos + 16), outputPos); return encryptedData; } getAvcDecryptedUnit(decodedData, decryptedData) { const uint8DecryptedData = new Uint8Array(decryptedData); let inputPos = 0; for (let outputPos = 32; outputPos < decodedData.length - 16; outputPos += 160, inputPos += 16) decodedData.set(uint8DecryptedData.subarray(inputPos, inputPos + 16), outputPos); return decodedData; } decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit) { const decodedData = discardEPB(curUnit.data); const encryptedData = this.getAvcEncryptedData(decodedData); this.decryptBuffer(encryptedData.buffer).then((decryptedBuffer) => { curUnit.data = this.getAvcDecryptedUnit(decodedData, decryptedBuffer); if (!this.decrypter.isSync()) this.decryptAvcSamples(samples, sampleIndex, unitIndex + 1, callback); }).catch(callback); } decryptAvcSamples(samples, sampleIndex, unitIndex, callback) { if (samples instanceof Uint8Array) throw new Error("Cannot decrypt samples of type Uint8Array"); for (;; sampleIndex++, unitIndex = 0) { if (sampleIndex >= samples.length) { callback(); return; } const curUnits = samples[sampleIndex].units; for (;; unitIndex++) { if (unitIndex >= curUnits.length) break; const curUnit = curUnits[unitIndex]; if (curUnit.data.length <= 48 || curUnit.type !== 1 && curUnit.type !== 5) continue; this.decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit); if (!this.decrypter.isSync()) return; } } } }; var BaseVideoParser = class { constructor() { this.VideoSample = null; } createVideoSample(key, pts, dts) { return { key, frame: false, pts, dts, units: [], length: 0 }; } getLastNalUnit(samples) { var _VideoSample; let VideoSample = this.VideoSample; let lastUnit; if (!VideoSample || VideoSample.units.length === 0) VideoSample = samples[samples.length - 1]; if ((_VideoSample = VideoSample) != null && _VideoSample.units) { const units = VideoSample.units; lastUnit = units[units.length - 1]; } return lastUnit; } pushAccessUnit(VideoSample, videoTrack) { if (VideoSample.units.length && VideoSample.frame) { if (VideoSample.pts === void 0) { const samples = videoTrack.samples; const nbSamples = samples.length; if (nbSamples) { const lastSample = samples[nbSamples - 1]; VideoSample.pts = lastSample.pts; VideoSample.dts = lastSample.dts; } else { videoTrack.dropped++; return; } } videoTrack.samples.push(VideoSample); } } parseNALu(track, array, endOfSegment) { const len = array.byteLength; let state = track.naluState || 0; const lastState = state; const units = []; let i = 0; let value; let overflow; let unitType; let lastUnitStart = -1; let lastUnitType = 0; if (state === -1) { lastUnitStart = 0; lastUnitType = this.getNALuType(array, 0); state = 0; i = 1; } while (i < len) { value = array[i++]; if (!state) { state = value ? 0 : 1; continue; } if (state === 1) { state = value ? 0 : 2; continue; } if (!value) state = 3; else if (value === 1) { overflow = i - state - 1; if (lastUnitStart >= 0) { const unit = { data: array.subarray(lastUnitStart, overflow), type: lastUnitType }; units.push(unit); } else { const lastUnit = this.getLastNalUnit(track.samples); if (lastUnit) { if (lastState && i <= 4 - lastState) { if (lastUnit.state) lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState); } if (overflow > 0) { lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow)); lastUnit.state = 0; } } } if (i < len) { unitType = this.getNALuType(array, i); lastUnitStart = i; lastUnitType = unitType; state = 0; } else state = -1; } else state = 0; } if (lastUnitStart >= 0 && state >= 0) { const unit = { data: array.subarray(lastUnitStart, len), type: lastUnitType, state }; units.push(unit); } if (units.length === 0) { const lastUnit = this.getLastNalUnit(track.samples); if (lastUnit) lastUnit.data = appendUint8Array(lastUnit.data, array); } track.naluState = state; return units; } }; /** * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264. */ var ExpGolomb = class { constructor(data) { this.data = void 0; this.bytesAvailable = void 0; this.word = void 0; this.bitsAvailable = void 0; this.data = data; this.bytesAvailable = data.byteLength; this.word = 0; this.bitsAvailable = 0; } loadWord() { const data = this.data; const bytesAvailable = this.bytesAvailable; const position = data.byteLength - bytesAvailable; const workingBytes = new Uint8Array(4); const availableBytes = Math.min(4, bytesAvailable); if (availableBytes === 0) throw new Error("no bytes available"); workingBytes.set(data.subarray(position, position + availableBytes)); this.word = new DataView(workingBytes.buffer).getUint32(0); this.bitsAvailable = availableBytes * 8; this.bytesAvailable -= availableBytes; } skipBits(count) { let skipBytes; count = Math.min(count, this.bytesAvailable * 8 + this.bitsAvailable); if (this.bitsAvailable > count) { this.word <<= count; this.bitsAvailable -= count; } else { count -= this.bitsAvailable; skipBytes = count >> 3; count -= skipBytes << 3; this.bytesAvailable -= skipBytes; this.loadWord(); this.word <<= count; this.bitsAvailable -= count; } } readBits(size) { let bits = Math.min(this.bitsAvailable, size); const valu = this.word >>> 32 - bits; if (size > 32) logger.error("Cannot read more than 32 bits at a time"); this.bitsAvailable -= bits; if (this.bitsAvailable > 0) this.word <<= bits; else if (this.bytesAvailable > 0) this.loadWord(); else throw new Error("no bits available"); bits = size - bits; if (bits > 0 && this.bitsAvailable) return valu << bits | this.readBits(bits); else return valu; } skipLZ() { let leadingZeroCount; for (leadingZeroCount = 0; leadingZeroCount < this.bitsAvailable; ++leadingZeroCount) if ((this.word & 2147483648 >>> leadingZeroCount) !== 0) { this.word <<= leadingZeroCount; this.bitsAvailable -= leadingZeroCount; return leadingZeroCount; } this.loadWord(); return leadingZeroCount + this.skipLZ(); } skipUEG() { this.skipBits(1 + this.skipLZ()); } skipEG() { this.skipBits(1 + this.skipLZ()); } readUEG() { const clz = this.skipLZ(); return this.readBits(clz + 1) - 1; } readEG() { const valu = this.readUEG(); if (1 & valu) return 1 + valu >>> 1; else return -1 * (valu >>> 1); } readBoolean() { return this.readBits(1) === 1; } readUByte() { return this.readBits(8); } readUShort() { return this.readBits(16); } readUInt() { return this.readBits(32); } }; var AvcVideoParser = class extends BaseVideoParser { parsePES(track, textTrack, pes, endOfSegment) { const units = this.parseNALu(track, pes.data, endOfSegment); let VideoSample = this.VideoSample; let push; let spsfound = false; pes.data = null; if (VideoSample && units.length && !track.audFound) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts); } units.forEach((unit) => { var _VideoSample2, _VideoSample3; switch (unit.type) { case 1: { let iskey = false; push = true; const data = unit.data; if (spsfound && data.length > 4) { const sliceType = this.readSliceType(data); if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) iskey = true; } if (iskey) { var _VideoSample; if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = null; } } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(true, pes.pts, pes.dts); VideoSample.frame = true; VideoSample.key = iskey; break; } case 5: push = true; if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = null; } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(true, pes.pts, pes.dts); VideoSample.key = true; VideoSample.frame = true; break; case 6: push = true; parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples); break; case 7: { var _track$pixelRatio, _track$pixelRatio2; push = true; spsfound = true; const sps = unit.data; const config = this.readSPS(sps); if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) { track.width = config.width; track.height = config.height; track.pixelRatio = config.pixelRatio; track.sps = [sps]; const codecarray = sps.subarray(1, 4); let codecstring = "avc1."; for (let i = 0; i < 3; i++) { let h = codecarray[i].toString(16); if (h.length < 2) h = "0" + h; codecstring += h; } track.codec = codecstring; } break; } case 8: push = true; track.pps = [unit.data]; break; case 9: push = true; track.audFound = true; if ((_VideoSample3 = VideoSample) != null && _VideoSample3.frame) { this.pushAccessUnit(VideoSample, track); VideoSample = null; } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts); break; case 12: push = true; break; default: push = false; break; } if (VideoSample && push) VideoSample.units.push(unit); }); if (endOfSegment && VideoSample) { this.pushAccessUnit(VideoSample, track); this.VideoSample = null; } } getNALuType(data, offset) { return data[offset] & 31; } readSliceType(data) { const eg = new ExpGolomb(data); eg.readUByte(); eg.readUEG(); return eg.readUEG(); } /** * The scaling list is optionally transmitted as part of a sequence parameter * set and is not relevant to transmuxing. * @param count the number of entries in this scaling list * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1 */ skipScalingList(count, reader) { let lastScale = 8; let nextScale = 8; let deltaScale; for (let j = 0; j < count; j++) { if (nextScale !== 0) { deltaScale = reader.readEG(); nextScale = (lastScale + deltaScale + 256) % 256; } lastScale = nextScale === 0 ? lastScale : nextScale; } } /** * Read a sequence parameter set and return some interesting video * properties. A sequence parameter set is the H264 metadata that * describes the properties of upcoming video frames. * @returns an object with configuration parsed from the * sequence parameter set, including the dimensions of the * associated video frames. */ readSPS(sps) { const eg = new ExpGolomb(sps); let frameCropLeftOffset = 0; let frameCropRightOffset = 0; let frameCropTopOffset = 0; let frameCropBottomOffset = 0; let numRefFramesInPicOrderCntCycle; let scalingListCount; let i; const readUByte = eg.readUByte.bind(eg); const readBits = eg.readBits.bind(eg); const readUEG = eg.readUEG.bind(eg); const readBoolean = eg.readBoolean.bind(eg); const skipBits = eg.skipBits.bind(eg); const skipEG = eg.skipEG.bind(eg); const skipUEG = eg.skipUEG.bind(eg); const skipScalingList = this.skipScalingList.bind(this); readUByte(); const profileIdc = readUByte(); readBits(5); skipBits(3); readUByte(); skipUEG(); if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) { const chromaFormatIdc = readUEG(); if (chromaFormatIdc === 3) skipBits(1); skipUEG(); skipUEG(); skipBits(1); if (readBoolean()) { scalingListCount = chromaFormatIdc !== 3 ? 8 : 12; for (i = 0; i < scalingListCount; i++) if (readBoolean()) if (i < 6) skipScalingList(16, eg); else skipScalingList(64, eg); } } skipUEG(); const picOrderCntType = readUEG(); if (picOrderCntType === 0) readUEG(); else if (picOrderCntType === 1) { skipBits(1); skipEG(); skipEG(); numRefFramesInPicOrderCntCycle = readUEG(); for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) skipEG(); } skipUEG(); skipBits(1); const picWidthInMbsMinus1 = readUEG(); const picHeightInMapUnitsMinus1 = readUEG(); const frameMbsOnlyFlag = readBits(1); if (frameMbsOnlyFlag === 0) skipBits(1); skipBits(1); if (readBoolean()) { frameCropLeftOffset = readUEG(); frameCropRightOffset = readUEG(); frameCropTopOffset = readUEG(); frameCropBottomOffset = readUEG(); } let pixelRatio = [1, 1]; if (readBoolean()) { if (readBoolean()) switch (readUByte()) { case 1: pixelRatio = [1, 1]; break; case 2: pixelRatio = [12, 11]; break; case 3: pixelRatio = [10, 11]; break; case 4: pixelRatio = [16, 11]; break; case 5: pixelRatio = [40, 33]; break; case 6: pixelRatio = [24, 11]; break; case 7: pixelRatio = [20, 11]; break; case 8: pixelRatio = [32, 11]; break; case 9: pixelRatio = [80, 33]; break; case 10: pixelRatio = [18, 11]; break; case 11: pixelRatio = [15, 11]; break; case 12: pixelRatio = [64, 33]; break; case 13: pixelRatio = [160, 99]; break; case 14: pixelRatio = [4, 3]; break; case 15: pixelRatio = [3, 2]; break; case 16: pixelRatio = [2, 1]; break; case 255: pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()]; break; } } return { width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2), height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset), pixelRatio }; } }; var HevcVideoParser = class extends BaseVideoParser { constructor(...args) { super(...args); this.initVPS = null; } parsePES(track, textTrack, pes, endOfSegment) { const units = this.parseNALu(track, pes.data, endOfSegment); let VideoSample = this.VideoSample; let push; let spsfound = false; pes.data = null; if (VideoSample && units.length && !track.audFound) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts); } units.forEach((unit) => { var _VideoSample2, _VideoSample3; switch (unit.type) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts); VideoSample.frame = true; push = true; break; case 16: case 17: case 18: case 21: push = true; if (spsfound) { var _VideoSample; if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = null; } } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(true, pes.pts, pes.dts); VideoSample.key = true; VideoSample.frame = true; break; case 19: case 20: push = true; if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) { this.pushAccessUnit(VideoSample, track); VideoSample = this.VideoSample = null; } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(true, pes.pts, pes.dts); VideoSample.key = true; VideoSample.frame = true; break; case 39: push = true; parseSEIMessageFromNALu(unit.data, 2, pes.pts, textTrack.samples); break; case 32: push = true; if (!track.vps) { if (typeof track.params !== "object") track.params = {}; track.params = _extends(track.params, this.readVPS(unit.data)); this.initVPS = unit.data; } track.vps = [unit.data]; break; case 33: push = true; spsfound = true; if (track.vps !== void 0 && track.vps[0] !== this.initVPS && track.sps !== void 0 && !this.matchSPS(track.sps[0], unit.data)) { this.initVPS = track.vps[0]; track.sps = track.pps = void 0; } if (!track.sps) { const config = this.readSPS(unit.data); track.width = config.width; track.height = config.height; track.pixelRatio = config.pixelRatio; track.codec = config.codecString; track.sps = []; if (typeof track.params !== "object") track.params = {}; for (const prop in config.params) track.params[prop] = config.params[prop]; } this.pushParameterSet(track.sps, unit.data, track.vps); if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(true, pes.pts, pes.dts); VideoSample.key = true; break; case 34: push = true; if (typeof track.params === "object") { if (!track.pps) { track.pps = []; const config = this.readPPS(unit.data); for (const prop in config) track.params[prop] = config[prop]; } this.pushParameterSet(track.pps, unit.data, track.vps); } break; case 35: push = true; track.audFound = true; if ((_VideoSample3 = VideoSample) != null && _VideoSample3.frame) { this.pushAccessUnit(VideoSample, track); VideoSample = null; } if (!VideoSample) VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts); break; default: push = false; break; } if (VideoSample && push) VideoSample.units.push(unit); }); if (endOfSegment && VideoSample) { this.pushAccessUnit(VideoSample, track); this.VideoSample = null; } } pushParameterSet(parameterSets, data, vps) { if (vps && vps[0] === this.initVPS || !vps && !parameterSets.length) parameterSets.push(data); } getNALuType(data, offset) { return (data[offset] & 126) >>> 1; } ebsp2rbsp(arr) { const dst = new Uint8Array(arr.byteLength); let dstIdx = 0; for (let i = 0; i < arr.byteLength; i++) { if (i >= 2) { if (arr[i] === 3 && arr[i - 1] === 0 && arr[i - 2] === 0) continue; } dst[dstIdx] = arr[i]; dstIdx++; } return new Uint8Array(dst.buffer, 0, dstIdx); } pushAccessUnit(VideoSample, videoTrack) { super.pushAccessUnit(VideoSample, videoTrack); if (this.initVPS) this.initVPS = null; } readVPS(vps) { const eg = new ExpGolomb(vps); eg.readUByte(); eg.readUByte(); eg.readBits(4); eg.skipBits(2); eg.readBits(6); const max_sub_layers_minus1 = eg.readBits(3); const temporal_id_nesting_flag = eg.readBoolean(); return { numTemporalLayers: max_sub_layers_minus1 + 1, temporalIdNested: temporal_id_nesting_flag }; } readSPS(sps) { const eg = new ExpGolomb(this.ebsp2rbsp(sps)); eg.readUByte(); eg.readUByte(); eg.readBits(4); const max_sub_layers_minus1 = eg.readBits(3); eg.readBoolean(); const general_profile_space = eg.readBits(2); const general_tier_flag = eg.readBoolean(); const general_profile_idc = eg.readBits(5); const general_profile_compatibility_flags_1 = eg.readUByte(); const general_profile_compatibility_flags_2 = eg.readUByte(); const general_profile_compatibility_flags_3 = eg.readUByte(); const general_profile_compatibility_flags_4 = eg.readUByte(); const general_constraint_indicator_flags_1 = eg.readUByte(); const general_constraint_indicator_flags_2 = eg.readUByte(); const general_constraint_indicator_flags_3 = eg.readUByte(); const general_constraint_indicator_flags_4 = eg.readUByte(); const general_constraint_indicator_flags_5 = eg.readUByte(); const general_constraint_indicator_flags_6 = eg.readUByte(); const general_level_idc = eg.readUByte(); const sub_layer_profile_present_flags = []; const sub_layer_level_present_flags = []; for (let i = 0; i < max_sub_layers_minus1; i++) { sub_layer_profile_present_flags.push(eg.readBoolean()); sub_layer_level_present_flags.push(eg.readBoolean()); } if (max_sub_layers_minus1 > 0) for (let i = max_sub_layers_minus1; i < 8; i++) eg.readBits(2); for (let i = 0; i < max_sub_layers_minus1; i++) { if (sub_layer_profile_present_flags[i]) { eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); eg.readUByte(); } if (sub_layer_level_present_flags[i]) eg.readUByte(); } eg.readUEG(); const chroma_format_idc = eg.readUEG(); if (chroma_format_idc == 3) eg.skipBits(1); const pic_width_in_luma_samples = eg.readUEG(); const pic_height_in_luma_samples = eg.readUEG(); const conformance_window_flag = eg.readBoolean(); let pic_left_offset = 0, pic_right_offset = 0, pic_top_offset = 0, pic_bottom_offset = 0; if (conformance_window_flag) { pic_left_offset += eg.readUEG(); pic_right_offset += eg.readUEG(); pic_top_offset += eg.readUEG(); pic_bottom_offset += eg.readUEG(); } const bit_depth_luma_minus8 = eg.readUEG(); const bit_depth_chroma_minus8 = eg.readUEG(); const log2_max_pic_order_cnt_lsb_minus4 = eg.readUEG(); const sub_layer_ordering_info_present_flag = eg.readBoolean(); for (let i = sub_layer_ordering_info_present_flag ? 0 : max_sub_layers_minus1; i <= max_sub_layers_minus1; i++) { eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); } eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); if (eg.readBoolean()) { if (eg.readBoolean()) for (let sizeId = 0; sizeId < 4; sizeId++) for (let matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) if (!eg.readBoolean()) eg.readUEG(); else { const coefNum = Math.min(64, 1 << 4 + (sizeId << 1)); if (sizeId > 1) eg.readEG(); for (let i = 0; i < coefNum; i++) eg.readEG(); } } eg.readBoolean(); eg.readBoolean(); if (eg.readBoolean()) { eg.readUByte(); eg.skipUEG(); eg.skipUEG(); eg.readBoolean(); } const num_short_term_ref_pic_sets = eg.readUEG(); let num_delta_pocs = 0; for (let i = 0; i < num_short_term_ref_pic_sets; i++) { let inter_ref_pic_set_prediction_flag = false; if (i !== 0) inter_ref_pic_set_prediction_flag = eg.readBoolean(); if (inter_ref_pic_set_prediction_flag) { if (i === num_short_term_ref_pic_sets) eg.readUEG(); eg.readBoolean(); eg.readUEG(); let next_num_delta_pocs = 0; for (let j = 0; j <= num_delta_pocs; j++) { const used_by_curr_pic_flag = eg.readBoolean(); let use_delta_flag = false; if (!used_by_curr_pic_flag) use_delta_flag = eg.readBoolean(); if (used_by_curr_pic_flag || use_delta_flag) next_num_delta_pocs++; } num_delta_pocs = next_num_delta_pocs; } else { const num_negative_pics = eg.readUEG(); const num_positive_pics = eg.readUEG(); num_delta_pocs = num_negative_pics + num_positive_pics; for (let j = 0; j < num_negative_pics; j++) { eg.readUEG(); eg.readBoolean(); } for (let j = 0; j < num_positive_pics; j++) { eg.readUEG(); eg.readBoolean(); } } } if (eg.readBoolean()) { const num_long_term_ref_pics_sps = eg.readUEG(); for (let i = 0; i < num_long_term_ref_pics_sps; i++) { for (let j = 0; j < log2_max_pic_order_cnt_lsb_minus4 + 4; j++) eg.readBits(1); eg.readBits(1); } } let min_spatial_segmentation_idc = 0; let sar_width = 1, sar_height = 1; let fps_fixed = true, fps_den = 1, fps_num = 0; eg.readBoolean(); eg.readBoolean(); let default_display_window_flag = false; if (eg.readBoolean()) { if (eg.readBoolean()) { const aspect_ratio_idc = eg.readUByte(); const sar_width_table = [ 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2 ]; const sar_height_table = [ 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1 ]; if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) { sar_width = sar_width_table[aspect_ratio_idc - 1]; sar_height = sar_height_table[aspect_ratio_idc - 1]; } else if (aspect_ratio_idc === 255) { sar_width = eg.readBits(16); sar_height = eg.readBits(16); } } if (eg.readBoolean()) eg.readBoolean(); if (eg.readBoolean()) { eg.readBits(3); eg.readBoolean(); if (eg.readBoolean()) { eg.readUByte(); eg.readUByte(); eg.readUByte(); } } if (eg.readBoolean()) { eg.readUEG(); eg.readUEG(); } eg.readBoolean(); eg.readBoolean(); eg.readBoolean(); default_display_window_flag = eg.readBoolean(); if (default_display_window_flag) { eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); eg.skipUEG(); } if (eg.readBoolean()) { fps_den = eg.readBits(32); fps_num = eg.readBits(32); if (eg.readBoolean()) eg.readUEG(); if (eg.readBoolean()) { const nal_hrd_parameters_present_flag = eg.readBoolean(); const vcl_hrd_parameters_present_flag = eg.readBoolean(); let sub_pic_hrd_params_present_flag = false; if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) { sub_pic_hrd_params_present_flag = eg.readBoolean(); if (sub_pic_hrd_params_present_flag) { eg.readUByte(); eg.readBits(5); eg.readBoolean(); eg.readBits(5); } eg.readBits(4); eg.readBits(4); if (sub_pic_hrd_params_present_flag) eg.readBits(4); eg.readBits(5); eg.readBits(5); eg.readBits(5); } for (let i = 0; i <= max_sub_layers_minus1; i++) { fps_fixed = eg.readBoolean(); const fixed_pic_rate_within_cvs_flag = fps_fixed || eg.readBoolean(); let low_delay_hrd_flag = false; if (fixed_pic_rate_within_cvs_flag) eg.readEG(); else low_delay_hrd_flag = eg.readBoolean(); const cpb_cnt = low_delay_hrd_flag ? 1 : eg.readUEG() + 1; if (nal_hrd_parameters_present_flag) for (let j = 0; j < cpb_cnt; j++) { eg.readUEG(); eg.readUEG(); if (sub_pic_hrd_params_present_flag) { eg.readUEG(); eg.readUEG(); } eg.skipBits(1); } if (vcl_hrd_parameters_present_flag) for (let j = 0; j < cpb_cnt; j++) { eg.readUEG(); eg.readUEG(); if (sub_pic_hrd_params_present_flag) { eg.readUEG(); eg.readUEG(); } eg.skipBits(1); } } } } if (eg.readBoolean()) { eg.readBoolean(); eg.readBoolean(); eg.readBoolean(); min_spatial_segmentation_idc = eg.readUEG(); } } let width = pic_width_in_luma_samples, height = pic_height_in_luma_samples; if (conformance_window_flag) { let chroma_scale_w = 1, chroma_scale_h = 1; if (chroma_format_idc === 1) chroma_scale_w = chroma_scale_h = 2; else if (chroma_format_idc == 2) chroma_scale_w = 2; width = pic_width_in_luma_samples - chroma_scale_w * pic_right_offset - chroma_scale_w * pic_left_offset; height = pic_height_in_luma_samples - chroma_scale_h * pic_bottom_offset - chroma_scale_h * pic_top_offset; } const profile_space_string = general_profile_space ? [ "A", "B", "C" ][general_profile_space] : ""; const profile_compatibility_buf = general_profile_compatibility_flags_1 << 24 | general_profile_compatibility_flags_2 << 16 | general_profile_compatibility_flags_3 << 8 | general_profile_compatibility_flags_4; let profile_compatibility_rev = 0; for (let i = 0; i < 32; i++) profile_compatibility_rev = (profile_compatibility_rev | (profile_compatibility_buf >> i & 1) << 31 - i) >>> 0; let profile_compatibility_flags_string = profile_compatibility_rev.toString(16); if (general_profile_idc === 1 && profile_compatibility_flags_string === "2") profile_compatibility_flags_string = "6"; return { codecString: `hvc1.${profile_space_string}${general_profile_idc}.${profile_compatibility_flags_string}.${general_tier_flag ? "H" : "L"}${general_level_idc}.B0`, params: { general_tier_flag, general_profile_idc, general_profile_space, general_profile_compatibility_flags: [ general_profile_compatibility_flags_1, general_profile_compatibility_flags_2, general_profile_compatibility_flags_3, general_profile_compatibility_flags_4 ], general_constraint_indicator_flags: [ general_constraint_indicator_flags_1, general_constraint_indicator_flags_2, general_constraint_indicator_flags_3, general_constraint_indicator_flags_4, general_constraint_indicator_flags_5, general_constraint_indicator_flags_6 ], general_level_idc, bit_depth: bit_depth_luma_minus8 + 8, bit_depth_luma_minus8, bit_depth_chroma_minus8, min_spatial_segmentation_idc, chroma_format_idc, frame_rate: { fixed: fps_fixed, fps: fps_num / fps_den } }, width, height, pixelRatio: [sar_width, sar_height] }; } readPPS(pps) { const eg = new ExpGolomb(this.ebsp2rbsp(pps)); eg.readUByte(); eg.readUByte(); eg.skipUEG(); eg.skipUEG(); eg.skipBits(2); eg.skipBits(3); eg.skipBits(2); eg.skipUEG(); eg.skipUEG(); eg.skipEG(); eg.skipBits(2); if (eg.readBoolean()) eg.skipUEG(); eg.skipEG(); eg.skipEG(); eg.skipBits(4); const tiles_enabled_flag = eg.readBoolean(); const entropy_coding_sync_enabled_flag = eg.readBoolean(); let parallelismType = 1; if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) parallelismType = 0; else if (entropy_coding_sync_enabled_flag) parallelismType = 3; else if (tiles_enabled_flag) parallelismType = 2; return { parallelismType }; } matchSPS(sps1, sps2) { return String.fromCharCode.apply(null, sps1).substr(3) === String.fromCharCode.apply(null, sps2).substr(3); } }; var PACKET_LENGTH = 188; var TSDemuxer = class TSDemuxer { constructor(observer, config, typeSupported, logger) { this.logger = void 0; this.observer = void 0; this.config = void 0; this.typeSupported = void 0; this.sampleAes = null; this.pmtParsed = false; this.audioCodec = void 0; this.videoCodec = void 0; this._pmtId = -1; this._videoTrack = void 0; this._audioTrack = void 0; this._id3Track = void 0; this._txtTrack = void 0; this.aacOverFlow = null; this.remainderData = null; this.videoParser = void 0; this.observer = observer; this.config = config; this.typeSupported = typeSupported; this.logger = logger; this.videoParser = null; } static probe(data, logger) { const syncOffset = TSDemuxer.syncOffset(data); if (syncOffset > 0) logger.warn(`MPEG2-TS detected but first sync word found @ offset ${syncOffset}`); return syncOffset !== -1; } static syncOffset(data) { const length = data.length; let scanwindow = Math.min(PACKET_LENGTH * 5, length - PACKET_LENGTH) + 1; let i = 0; while (i < scanwindow) { let foundPat = false; let packetStart = -1; let tsPackets = 0; for (let j = i; j < length; j += PACKET_LENGTH) if (data[j] === 71 && (length - j === PACKET_LENGTH || data[j + PACKET_LENGTH] === 71)) { tsPackets++; if (packetStart === -1) { packetStart = j; if (packetStart !== 0) scanwindow = Math.min(packetStart + PACKET_LENGTH * 99, data.length - PACKET_LENGTH) + 1; } if (!foundPat) foundPat = parsePID(data, j) === 0; if (foundPat && tsPackets > 1 && (packetStart === 0 && tsPackets > 2 || j + PACKET_LENGTH > scanwindow)) return packetStart; } else if (tsPackets) return -1; else break; i++; } return -1; } /** * Creates a track model internal to demuxer used to drive remuxing input */ static createTrack(type, duration) { return { container: type === "video" || type === "audio" ? "video/mp2t" : void 0, type, id: RemuxerTrackIdConfig[type], pid: -1, inputTimeScale: 9e4, sequenceNumber: 0, samples: [], dropped: 0, duration: type === "audio" ? duration : void 0 }; } /** * Initializes a new init segment on the demuxer/remuxer interface. Needed for discontinuities/track-switches (or at stream start) * Resets all internal track instances of the demuxer. */ resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) { this.pmtParsed = false; this._pmtId = -1; this._videoTrack = TSDemuxer.createTrack("video"); this._videoTrack.duration = trackDuration; this._audioTrack = TSDemuxer.createTrack("audio", trackDuration); this._id3Track = TSDemuxer.createTrack("id3"); this._txtTrack = TSDemuxer.createTrack("text"); this._audioTrack.segmentCodec = "aac"; this.videoParser = null; this.aacOverFlow = null; this.remainderData = null; this.audioCodec = audioCodec; this.videoCodec = videoCodec; } resetTimeStamp() {} resetContiguity() { const { _audioTrack, _videoTrack, _id3Track } = this; if (_audioTrack) _audioTrack.pesData = null; if (_videoTrack) _videoTrack.pesData = null; if (_id3Track) _id3Track.pesData = null; this.aacOverFlow = null; this.remainderData = null; } demux(data, timeOffset, isSampleAes = false, flush = false) { if (!isSampleAes) this.sampleAes = null; let pes; const videoTrack = this._videoTrack; const audioTrack = this._audioTrack; const id3Track = this._id3Track; const textTrack = this._txtTrack; let videoPid = videoTrack.pid; let videoData = videoTrack.pesData; let audioPid = audioTrack.pid; let id3Pid = id3Track.pid; let audioData = audioTrack.pesData; let id3Data = id3Track.pesData; let unknownPID = null; let pmtParsed = this.pmtParsed; let pmtId = this._pmtId; let len = data.length; if (this.remainderData) { data = appendUint8Array(this.remainderData, data); len = data.length; this.remainderData = null; } if (len < PACKET_LENGTH && !flush) { this.remainderData = data; return { audioTrack, videoTrack, id3Track, textTrack }; } const syncOffset = Math.max(0, TSDemuxer.syncOffset(data)); len -= (len - syncOffset) % PACKET_LENGTH; if (len < data.byteLength && !flush) this.remainderData = new Uint8Array(data.buffer, len, data.buffer.byteLength - len); let tsPacketErrors = 0; for (let start = syncOffset; start < len; start += PACKET_LENGTH) if (data[start] === 71) { const stt = !!(data[start + 1] & 64); const pid = parsePID(data, start); const atf = (data[start + 3] & 48) >> 4; let offset; if (atf > 1) { offset = start + 5 + data[start + 4]; if (offset === start + PACKET_LENGTH) continue; } else offset = start + 4; switch (pid) { case videoPid: if (stt) { if (videoData && (pes = parsePES(videoData, this.logger))) { this.readyVideoParser(videoTrack.segmentCodec); if (this.videoParser !== null) this.videoParser.parsePES(videoTrack, textTrack, pes, false); } videoData = { data: [], size: 0 }; } if (videoData) { videoData.data.push(data.subarray(offset, start + PACKET_LENGTH)); videoData.size += start + PACKET_LENGTH - offset; } break; case audioPid: if (stt) { if (audioData && (pes = parsePES(audioData, this.logger))) switch (audioTrack.segmentCodec) { case "aac": this.parseAACPES(audioTrack, pes); break; case "mp3": this.parseMPEGPES(audioTrack, pes); break; case "ac3": this.parseAC3PES(audioTrack, pes); break; } audioData = { data: [], size: 0 }; } if (audioData) { audioData.data.push(data.subarray(offset, start + PACKET_LENGTH)); audioData.size += start + PACKET_LENGTH - offset; } break; case id3Pid: if (stt) { if (id3Data && (pes = parsePES(id3Data, this.logger))) this.parseID3PES(id3Track, pes); id3Data = { data: [], size: 0 }; } if (id3Data) { id3Data.data.push(data.subarray(offset, start + PACKET_LENGTH)); id3Data.size += start + PACKET_LENGTH - offset; } break; case 0: if (stt) offset += data[offset] + 1; pmtId = this._pmtId = parsePAT(data, offset); break; case pmtId: { if (stt) offset += data[offset] + 1; const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer, this.logger); videoPid = parsedPIDs.videoPid; if (videoPid > 0) { videoTrack.pid = videoPid; videoTrack.segmentCodec = parsedPIDs.segmentVideoCodec; } audioPid = parsedPIDs.audioPid; if (audioPid > 0) { audioTrack.pid = audioPid; audioTrack.segmentCodec = parsedPIDs.segmentAudioCodec; } id3Pid = parsedPIDs.id3Pid; if (id3Pid > 0) id3Track.pid = id3Pid; if (unknownPID !== null && !pmtParsed) { this.logger.warn(`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`); unknownPID = null; start = syncOffset - 188; } pmtParsed = this.pmtParsed = true; break; } case 17: case 8191: break; default: unknownPID = pid; break; } } else tsPacketErrors++; if (tsPacketErrors > 0) emitParsingError(this.observer, /* @__PURE__ */ new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`), void 0, this.logger); videoTrack.pesData = videoData; audioTrack.pesData = audioData; id3Track.pesData = id3Data; const demuxResult = { audioTrack, videoTrack, id3Track, textTrack }; if (flush) this.extractRemainingSamples(demuxResult); return demuxResult; } flush() { const { remainderData } = this; this.remainderData = null; let result; if (remainderData) result = this.demux(remainderData, -1, false, true); else result = { videoTrack: this._videoTrack, audioTrack: this._audioTrack, id3Track: this._id3Track, textTrack: this._txtTrack }; this.extractRemainingSamples(result); if (this.sampleAes) return this.decrypt(result, this.sampleAes); return result; } extractRemainingSamples(demuxResult) { const { audioTrack, videoTrack, id3Track, textTrack } = demuxResult; const videoData = videoTrack.pesData; const audioData = audioTrack.pesData; const id3Data = id3Track.pesData; let pes; if (videoData && (pes = parsePES(videoData, this.logger))) { this.readyVideoParser(videoTrack.segmentCodec); if (this.videoParser !== null) { this.videoParser.parsePES(videoTrack, textTrack, pes, true); videoTrack.pesData = null; } } else videoTrack.pesData = videoData; if (audioData && (pes = parsePES(audioData, this.logger))) { switch (audioTrack.segmentCodec) { case "aac": this.parseAACPES(audioTrack, pes); break; case "mp3": this.parseMPEGPES(audioTrack, pes); break; case "ac3": this.parseAC3PES(audioTrack, pes); break; } audioTrack.pesData = null; } else { if (audioData != null && audioData.size) this.logger.log("last AAC PES packet truncated,might overlap between fragments"); audioTrack.pesData = audioData; } if (id3Data && (pes = parsePES(id3Data, this.logger))) { this.parseID3PES(id3Track, pes); id3Track.pesData = null; } else id3Track.pesData = id3Data; } demuxSampleAes(data, keyData, timeOffset) { const demuxResult = this.demux(data, timeOffset, true, !this.config.progressive); const sampleAes = this.sampleAes = new SampleAesDecrypter(this.observer, this.config, keyData); return this.decrypt(demuxResult, sampleAes); } readyVideoParser(codec) { if (this.videoParser === null) { if (codec === "avc") this.videoParser = new AvcVideoParser(); else if (codec === "hevc") this.videoParser = new HevcVideoParser(); } } decrypt(demuxResult, sampleAes) { return new Promise((resolve) => { const { audioTrack, videoTrack } = demuxResult; if (audioTrack.samples && audioTrack.segmentCodec === "aac") sampleAes.decryptAacSamples(audioTrack.samples, 0, () => { if (videoTrack.samples) sampleAes.decryptAvcSamples(videoTrack.samples, 0, 0, () => { resolve(demuxResult); }); else resolve(demuxResult); }); else if (videoTrack.samples) sampleAes.decryptAvcSamples(videoTrack.samples, 0, 0, () => { resolve(demuxResult); }); }); } destroy() { if (this.observer) this.observer.removeAllListeners(); this.config = this.logger = this.observer = null; this.aacOverFlow = this.videoParser = this.remainderData = this.sampleAes = null; this._videoTrack = this._audioTrack = this._id3Track = this._txtTrack = void 0; } parseAACPES(track, pes) { let startOffset = 0; const aacOverFlow = this.aacOverFlow; let data = pes.data; if (aacOverFlow) { this.aacOverFlow = null; const frameMissingBytes = aacOverFlow.missing; const sampleLength = aacOverFlow.sample.unit.byteLength; if (frameMissingBytes === -1) data = appendUint8Array(aacOverFlow.sample.unit, data); else { const frameOverflowBytes = sampleLength - frameMissingBytes; aacOverFlow.sample.unit.set(data.subarray(0, frameMissingBytes), frameOverflowBytes); track.samples.push(aacOverFlow.sample); startOffset = aacOverFlow.missing; } } let offset; let len; for (offset = startOffset, len = data.length; offset < len - 1; offset++) if (isHeader$1(data, offset)) break; if (offset !== startOffset) { let reason; const recoverable = offset < len - 1; if (recoverable) reason = `AAC PES did not start with ADTS header,offset:${offset}`; else reason = "No ADTS header found in AAC PES"; emitParsingError(this.observer, new Error(reason), recoverable, this.logger); if (!recoverable) return; } initTrackConfig(track, this.observer, data, offset, this.audioCodec); let pts; if (pes.pts !== void 0) pts = pes.pts; else if (aacOverFlow) { const frameDuration = getFrameDuration(track.samplerate); pts = aacOverFlow.sample.pts + frameDuration; } else { this.logger.warn("[tsdemuxer]: AAC PES unknown PTS"); return; } let frameIndex = 0; let frame; while (offset < len) { frame = appendFrame$2(track, data, offset, pts, frameIndex); offset += frame.length; if (!frame.missing) { frameIndex++; for (; offset < len - 1; offset++) if (isHeader$1(data, offset)) break; } else { this.aacOverFlow = frame; break; } } } parseMPEGPES(track, pes) { const data = pes.data; const length = data.length; let frameIndex = 0; let offset = 0; const pts = pes.pts; if (pts === void 0) { this.logger.warn("[tsdemuxer]: MPEG PES unknown PTS"); return; } while (offset < length) if (isHeader(data, offset)) { const frame = appendFrame$1(track, data, offset, pts, frameIndex); if (frame) { offset += frame.length; frameIndex++; } else break; } else offset++; } parseAC3PES(track, pes) { { const data = pes.data; const pts = pes.pts; if (pts === void 0) { this.logger.warn("[tsdemuxer]: AC3 PES unknown PTS"); return; } const length = data.length; let frameIndex = 0; let offset = 0; let parsed; while (offset < length && (parsed = appendFrame(track, data, offset, pts, frameIndex++)) > 0) offset += parsed; } } parseID3PES(id3Track, pes) { if (pes.pts === void 0) { this.logger.warn("[tsdemuxer]: ID3 PES unknown PTS"); return; } const id3Sample = _extends({}, pes, { type: this._videoTrack ? MetadataSchema.emsg : MetadataSchema.audioId3, duration: Number.POSITIVE_INFINITY }); id3Track.samples.push(id3Sample); } }; function parsePID(data, offset) { return ((data[offset + 1] & 31) << 8) + data[offset + 2]; } function parsePAT(data, offset) { return (data[offset + 10] & 31) << 8 | data[offset + 11]; } function parsePMT(data, offset, typeSupported, isSampleAes, observer, logger) { const result = { audioPid: -1, videoPid: -1, id3Pid: -1, segmentVideoCodec: "avc", segmentAudioCodec: "aac" }; const sectionLength = (data[offset + 1] & 15) << 8 | data[offset + 2]; const tableEnd = offset + 3 + sectionLength - 4; const programInfoLength = (data[offset + 10] & 15) << 8 | data[offset + 11]; offset += 12 + programInfoLength; while (offset < tableEnd) { const pid = parsePID(data, offset); const esInfoLength = (data[offset + 3] & 15) << 8 | data[offset + 4]; switch (data[offset]) { case 207: if (!isSampleAes) { logEncryptedSamplesFoundInUnencryptedStream("ADTS AAC", logger); break; } case 15: if (result.audioPid === -1) result.audioPid = pid; break; case 21: if (result.id3Pid === -1) result.id3Pid = pid; break; case 219: if (!isSampleAes) { logEncryptedSamplesFoundInUnencryptedStream("H.264", logger); break; } case 27: if (result.videoPid === -1) result.videoPid = pid; break; case 3: case 4: if (!typeSupported.mpeg && !typeSupported.mp3) logger.log("MPEG audio found, not supported in this browser"); else if (result.audioPid === -1) { result.audioPid = pid; result.segmentAudioCodec = "mp3"; } break; case 193: if (!isSampleAes) { logEncryptedSamplesFoundInUnencryptedStream("AC-3", logger); break; } case 129: if (!typeSupported.ac3) logger.log("AC-3 audio found, not supported in this browser"); else if (result.audioPid === -1) { result.audioPid = pid; result.segmentAudioCodec = "ac3"; } break; case 6: if (result.audioPid === -1 && esInfoLength > 0) { let parsePos = offset + 5; let remaining = esInfoLength; while (remaining > 2) { switch (data[parsePos]) { case 106: if (typeSupported.ac3 !== true) logger.log("AC-3 audio found, not supported in this browser for now"); else { result.audioPid = pid; result.segmentAudioCodec = "ac3"; } break; } const descriptorLen = data[parsePos + 1] + 2; parsePos += descriptorLen; remaining -= descriptorLen; } } break; case 194: case 135: emitParsingError(observer, /* @__PURE__ */ new Error("Unsupported EC-3 in M2TS found"), void 0, logger); return result; case 36: if (result.videoPid === -1) { result.videoPid = pid; result.segmentVideoCodec = "hevc"; logger.log("HEVC in M2TS found"); } break; } offset += esInfoLength + 5; } return result; } function emitParsingError(observer, error, levelRetry, logger) { logger.warn(`parsing error: ${error.message}`); observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, levelRetry, error, reason: error.message }); } function logEncryptedSamplesFoundInUnencryptedStream(type, logger) { logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`); } function parsePES(stream, logger) { let i = 0; let frag; let pesLen; let pesHdrLen; let pesPts; let pesDts; const data = stream.data; if (!stream || stream.size === 0) return null; while (data[0].length < 19 && data.length > 1) { data[0] = appendUint8Array(data[0], data[1]); data.splice(1, 1); } frag = data[0]; if ((frag[0] << 16) + (frag[1] << 8) + frag[2] === 1) { pesLen = (frag[4] << 8) + frag[5]; if (pesLen && pesLen > stream.size - 6) return null; const pesFlags = frag[7]; if (pesFlags & 192) { pesPts = (frag[9] & 14) * 536870912 + (frag[10] & 255) * 4194304 + (frag[11] & 254) * 16384 + (frag[12] & 255) * 128 + (frag[13] & 254) / 2; if (pesFlags & 64) { pesDts = (frag[14] & 14) * 536870912 + (frag[15] & 255) * 4194304 + (frag[16] & 254) * 16384 + (frag[17] & 255) * 128 + (frag[18] & 254) / 2; if (pesPts - pesDts > 60 * 9e4) { logger.warn(`${Math.round((pesPts - pesDts) / 9e4)}s delta between PTS and DTS, align them`); pesPts = pesDts; } } else pesDts = pesPts; } pesHdrLen = frag[8]; let payloadStartOffset = pesHdrLen + 9; if (stream.size <= payloadStartOffset) return null; stream.size -= payloadStartOffset; const pesData = new Uint8Array(stream.size); for (let j = 0, dataLen = data.length; j < dataLen; j++) { frag = data[j]; let len = frag.byteLength; if (payloadStartOffset) if (payloadStartOffset > len) { payloadStartOffset -= len; continue; } else { frag = frag.subarray(payloadStartOffset); len -= payloadStartOffset; payloadStartOffset = 0; } pesData.set(frag, i); i += len; } if (pesLen) pesLen -= pesHdrLen + 3; return { data: pesData, pts: pesPts, dts: pesDts, len: pesLen }; } return null; } /** * AAC helper */ var AAC = class { static getSilentFrame(codec, channelCount) { switch (codec) { case "mp4a.40.2": if (channelCount === 1) return new Uint8Array([ 0, 200, 0, 128, 35, 128 ]); else if (channelCount === 2) return new Uint8Array([ 33, 0, 73, 144, 2, 25, 0, 35, 128 ]); else if (channelCount === 3) return new Uint8Array([ 0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 142 ]); else if (channelCount === 4) return new Uint8Array([ 0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 128, 44, 128, 8, 2, 56 ]); else if (channelCount === 5) return new Uint8Array([ 0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 56 ]); else if (channelCount === 6) return new Uint8Array([ 0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 0, 178, 0, 32, 8, 224 ]); break; default: if (channelCount === 1) return new Uint8Array([ 1, 64, 34, 128, 163, 78, 230, 128, 186, 8, 0, 0, 0, 28, 6, 241, 193, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94 ]); else if (channelCount === 2) return new Uint8Array([ 1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94 ]); else if (channelCount === 3) return new Uint8Array([ 1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94 ]); break; } } }; /** * Generate MP4 Box */ var UINT32_MAX = Math.pow(2, 32) - 1; var MP4 = class MP4 { static init() { MP4.types = { avc1: [], avcC: [], hvc1: [], hvcC: [], btrt: [], dinf: [], dref: [], esds: [], ftyp: [], hdlr: [], mdat: [], mdhd: [], mdia: [], mfhd: [], minf: [], moof: [], moov: [], mp4a: [], ".mp3": [], dac3: [], "ac-3": [], mvex: [], mvhd: [], pasp: [], sdtp: [], stbl: [], stco: [], stsc: [], stsd: [], stsz: [], stts: [], tfdt: [], tfhd: [], traf: [], trak: [], trun: [], trex: [], tkhd: [], vmhd: [], smhd: [] }; let i; for (i in MP4.types) if (MP4.types.hasOwnProperty(i)) MP4.types[i] = [ i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3) ]; MP4.HDLR_TYPES = { video: new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 118, 105, 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 105, 100, 101, 111, 72, 97, 110, 100, 108, 101, 114, 0 ]), audio: new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 115, 111, 117, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 117, 110, 100, 72, 97, 110, 100, 108, 101, 114, 0 ]) }; const dref = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 117, 114, 108, 32, 0, 0, 0, 1 ]); MP4.STTS = MP4.STSC = MP4.STCO = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0 ]); MP4.STSZ = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]); MP4.VMHD = new Uint8Array([ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ]); MP4.SMHD = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0 ]); MP4.STSD = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1 ]); const majorBrand = new Uint8Array([ 105, 115, 111, 109 ]); const avc1Brand = new Uint8Array([ 97, 118, 99, 49 ]); const minorVersion = new Uint8Array([ 0, 0, 0, 1 ]); MP4.FTYP = MP4.box(MP4.types.ftyp, majorBrand, minorVersion, majorBrand, avc1Brand); MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); } static box(type, ...payload) { let size = 8; let i = payload.length; const len = i; while (i--) size += payload[i].byteLength; const result = new Uint8Array(size); result[0] = size >> 24 & 255; result[1] = size >> 16 & 255; result[2] = size >> 8 & 255; result[3] = size & 255; result.set(type, 4); for (i = 0, size = 8; i < len; i++) { result.set(payload[i], size); size += payload[i].byteLength; } return result; } static hdlr(type) { return MP4.box(MP4.types.hdlr, MP4.HDLR_TYPES[type]); } static mdat(data) { return MP4.box(MP4.types.mdat, data); } static mdhd(timescale, duration) { duration *= timescale; const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)); const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); return MP4.box(MP4.types.mdhd, new Uint8Array([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, timescale >> 24 & 255, timescale >> 16 & 255, timescale >> 8 & 255, timescale & 255, upperWordDuration >> 24, upperWordDuration >> 16 & 255, upperWordDuration >> 8 & 255, upperWordDuration & 255, lowerWordDuration >> 24, lowerWordDuration >> 16 & 255, lowerWordDuration >> 8 & 255, lowerWordDuration & 255, 85, 196, 0, 0 ])); } static mdia(track) { return MP4.box(MP4.types.mdia, MP4.mdhd(track.timescale || 0, track.duration || 0), MP4.hdlr(track.type), MP4.minf(track)); } static mfhd(sequenceNumber) { return MP4.box(MP4.types.mfhd, new Uint8Array([ 0, 0, 0, 0, sequenceNumber >> 24, sequenceNumber >> 16 & 255, sequenceNumber >> 8 & 255, sequenceNumber & 255 ])); } static minf(track) { if (track.type === "audio") return MP4.box(MP4.types.minf, MP4.box(MP4.types.smhd, MP4.SMHD), MP4.DINF, MP4.stbl(track)); else return MP4.box(MP4.types.minf, MP4.box(MP4.types.vmhd, MP4.VMHD), MP4.DINF, MP4.stbl(track)); } static moof(sn, baseMediaDecodeTime, track) { return MP4.box(MP4.types.moof, MP4.mfhd(sn), MP4.traf(track, baseMediaDecodeTime)); } static moov(tracks) { let i = tracks.length; const boxes = []; while (i--) boxes[i] = MP4.trak(tracks[i]); return MP4.box.apply(null, [MP4.types.moov, MP4.mvhd(tracks[0].timescale || 0, tracks[0].duration || 0)].concat(boxes).concat(MP4.mvex(tracks))); } static mvex(tracks) { let i = tracks.length; const boxes = []; while (i--) boxes[i] = MP4.trex(tracks[i]); return MP4.box.apply(null, [MP4.types.mvex, ...boxes]); } static mvhd(timescale, duration) { duration *= timescale; const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)); const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); const bytes = new Uint8Array([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, timescale >> 24 & 255, timescale >> 16 & 255, timescale >> 8 & 255, timescale & 255, upperWordDuration >> 24, upperWordDuration >> 16 & 255, upperWordDuration >> 8 & 255, upperWordDuration & 255, lowerWordDuration >> 24, lowerWordDuration >> 16 & 255, lowerWordDuration >> 8 & 255, lowerWordDuration & 255, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255 ]); return MP4.box(MP4.types.mvhd, bytes); } static sdtp(track) { const samples = track.samples || []; const bytes = new Uint8Array(4 + samples.length); let i; let flags; for (i = 0; i < samples.length; i++) { flags = samples[i].flags; bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy; } return MP4.box(MP4.types.sdtp, bytes); } static stbl(track) { return MP4.box(MP4.types.stbl, MP4.stsd(track), MP4.box(MP4.types.stts, MP4.STTS), MP4.box(MP4.types.stsc, MP4.STSC), MP4.box(MP4.types.stsz, MP4.STSZ), MP4.box(MP4.types.stco, MP4.STCO)); } static avc1(track) { let sps = []; let pps = []; let i; let data; let len; for (i = 0; i < track.sps.length; i++) { data = track.sps[i]; len = data.byteLength; sps.push(len >>> 8 & 255); sps.push(len & 255); sps = sps.concat(Array.prototype.slice.call(data)); } for (i = 0; i < track.pps.length; i++) { data = track.pps[i]; len = data.byteLength; pps.push(len >>> 8 & 255); pps.push(len & 255); pps = pps.concat(Array.prototype.slice.call(data)); } const avcc = MP4.box(MP4.types.avcC, new Uint8Array([ 1, sps[3], sps[4], sps[5], 255, 224 | track.sps.length ].concat(sps).concat([track.pps.length]).concat(pps))); const width = track.width; const height = track.height; const hSpacing = track.pixelRatio[0]; const vSpacing = track.pixelRatio[1]; return MP4.box(MP4.types.avc1, new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, width >> 8 & 255, width & 255, height >> 8 & 255, height & 255, 0, 72, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1, 18, 100, 97, 105, 108, 121, 109, 111, 116, 105, 111, 110, 47, 104, 108, 115, 46, 106, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 17, 17 ]), avcc, MP4.box(MP4.types.btrt, new Uint8Array([ 0, 28, 156, 128, 0, 45, 198, 192, 0, 45, 198, 192 ])), MP4.box(MP4.types.pasp, new Uint8Array([ hSpacing >> 24, hSpacing >> 16 & 255, hSpacing >> 8 & 255, hSpacing & 255, vSpacing >> 24, vSpacing >> 16 & 255, vSpacing >> 8 & 255, vSpacing & 255 ]))); } static esds(track) { const config = track.config; return new Uint8Array([ 0, 0, 0, 0, 3, 25, 0, 1, 0, 4, 17, 64, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, ...config, 6, 1, 2 ]); } static audioStsd(track) { const samplerate = track.samplerate || 0; return new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, track.channelCount || 0, 0, 16, 0, 0, 0, 0, samplerate >> 8 & 255, samplerate & 255, 0, 0 ]); } static mp4a(track) { return MP4.box(MP4.types.mp4a, MP4.audioStsd(track), MP4.box(MP4.types.esds, MP4.esds(track))); } static mp3(track) { return MP4.box(MP4.types[".mp3"], MP4.audioStsd(track)); } static ac3(track) { return MP4.box(MP4.types["ac-3"], MP4.audioStsd(track), MP4.box(MP4.types.dac3, track.config)); } static stsd(track) { const { segmentCodec } = track; if (track.type === "audio") { if (segmentCodec === "aac") return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track)); if (segmentCodec === "ac3" && track.config) return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track)); if (segmentCodec === "mp3" && track.codec === "mp3") return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp3(track)); } else if (track.pps && track.sps) { if (segmentCodec === "avc") return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track)); if (segmentCodec === "hevc" && track.vps) return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track)); } else throw new Error(`video track missing pps or sps`); throw new Error(`unsupported ${track.type} segment codec (${segmentCodec}/${track.codec})`); } static tkhd(track) { const id = track.id; const duration = (track.duration || 0) * (track.timescale || 0); const width = track.width || 0; const height = track.height || 0; const upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)); const lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); return MP4.box(MP4.types.tkhd, new Uint8Array([ 1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, id >> 24 & 255, id >> 16 & 255, id >> 8 & 255, id & 255, 0, 0, 0, 0, upperWordDuration >> 24, upperWordDuration >> 16 & 255, upperWordDuration >> 8 & 255, upperWordDuration & 255, lowerWordDuration >> 24, lowerWordDuration >> 16 & 255, lowerWordDuration >> 8 & 255, lowerWordDuration & 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, width >> 8 & 255, width & 255, 0, 0, height >> 8 & 255, height & 255, 0, 0 ])); } static traf(track, baseMediaDecodeTime) { const sampleDependencyTable = MP4.sdtp(track); const id = track.id; const upperWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime / (UINT32_MAX + 1)); const lowerWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime % (UINT32_MAX + 1)); return MP4.box(MP4.types.traf, MP4.box(MP4.types.tfhd, new Uint8Array([ 0, 0, 0, 0, id >> 24, id >> 16 & 255, id >> 8 & 255, id & 255 ])), MP4.box(MP4.types.tfdt, new Uint8Array([ 1, 0, 0, 0, upperWordBaseMediaDecodeTime >> 24, upperWordBaseMediaDecodeTime >> 16 & 255, upperWordBaseMediaDecodeTime >> 8 & 255, upperWordBaseMediaDecodeTime & 255, lowerWordBaseMediaDecodeTime >> 24, lowerWordBaseMediaDecodeTime >> 16 & 255, lowerWordBaseMediaDecodeTime >> 8 & 255, lowerWordBaseMediaDecodeTime & 255 ])), MP4.trun(track, sampleDependencyTable.length + 16 + 20 + 8 + 16 + 8 + 8), sampleDependencyTable); } /** * Generate a track box. * @param track a track definition */ static trak(track) { track.duration = track.duration || 4294967295; return MP4.box(MP4.types.trak, MP4.tkhd(track), MP4.mdia(track)); } static trex(track) { const id = track.id; return MP4.box(MP4.types.trex, new Uint8Array([ 0, 0, 0, 0, id >> 24, id >> 16 & 255, id >> 8 & 255, id & 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 ])); } static trun(track, offset) { const samples = track.samples || []; const len = samples.length; const arraylen = 12 + 16 * len; const array = new Uint8Array(arraylen); let i; let sample; let duration; let size; let flags; let cts; offset += 8 + arraylen; array.set([ track.type === "video" ? 1 : 0, 0, 15, 1, len >>> 24 & 255, len >>> 16 & 255, len >>> 8 & 255, len & 255, offset >>> 24 & 255, offset >>> 16 & 255, offset >>> 8 & 255, offset & 255 ], 0); for (i = 0; i < len; i++) { sample = samples[i]; duration = sample.duration; size = sample.size; flags = sample.flags; cts = sample.cts; array.set([ duration >>> 24 & 255, duration >>> 16 & 255, duration >>> 8 & 255, duration & 255, size >>> 24 & 255, size >>> 16 & 255, size >>> 8 & 255, size & 255, flags.isLeading << 2 | flags.dependsOn, flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.paddingValue << 1 | flags.isNonSync, flags.degradPrio & 61440, flags.degradPrio & 15, cts >>> 24 & 255, cts >>> 16 & 255, cts >>> 8 & 255, cts & 255 ], 12 + 16 * i); } return MP4.box(MP4.types.trun, array); } static initSegment(tracks) { if (!MP4.types) MP4.init(); const movie = MP4.moov(tracks); return appendUint8Array(MP4.FTYP, movie); } static hvc1(track) { const ps = track.params; const units = [ track.vps, track.sps, track.pps ]; const config = new Uint8Array([ 1, ps.general_profile_space << 6 | (ps.general_tier_flag ? 32 : 0) | ps.general_profile_idc, ps.general_profile_compatibility_flags[0], ps.general_profile_compatibility_flags[1], ps.general_profile_compatibility_flags[2], ps.general_profile_compatibility_flags[3], ps.general_constraint_indicator_flags[0], ps.general_constraint_indicator_flags[1], ps.general_constraint_indicator_flags[2], ps.general_constraint_indicator_flags[3], ps.general_constraint_indicator_flags[4], ps.general_constraint_indicator_flags[5], ps.general_level_idc, 240 | ps.min_spatial_segmentation_idc >> 8, 255 & ps.min_spatial_segmentation_idc, 252 | ps.parallelismType, 252 | ps.chroma_format_idc, 248 | ps.bit_depth_luma_minus8, 248 | ps.bit_depth_chroma_minus8, 0, parseInt(ps.frame_rate.fps), 3 | ps.temporal_id_nested << 2 | ps.num_temporal_layers << 3 | (ps.frame_rate.fixed ? 64 : 0), units.length ]); let length = config.length; for (let i = 0; i < units.length; i += 1) { length += 3; for (let j = 0; j < units[i].length; j += 1) length += 2 + units[i][j].length; } const hvcC = new Uint8Array(length); hvcC.set(config, 0); length = config.length; const iMax = units.length - 1; for (let i = 0; i < units.length; i += 1) { hvcC.set(new Uint8Array([ 32 + i | (i === iMax ? 128 : 0), 0, units[i].length ]), length); length += 3; for (let j = 0; j < units[i].length; j += 1) { hvcC.set(new Uint8Array([units[i][j].length >> 8, units[i][j].length & 255]), length); length += 2; hvcC.set(units[i][j], length); length += units[i][j].length; } } const hvcc = MP4.box(MP4.types.hvcC, hvcC); const width = track.width; const height = track.height; const hSpacing = track.pixelRatio[0]; const vSpacing = track.pixelRatio[1]; return MP4.box(MP4.types.hvc1, new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, width >> 8 & 255, width & 255, height >> 8 & 255, height & 255, 0, 72, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1, 18, 100, 97, 105, 108, 121, 109, 111, 116, 105, 111, 110, 47, 104, 108, 115, 46, 106, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 17, 17 ]), hvcc, MP4.box(MP4.types.btrt, new Uint8Array([ 0, 28, 156, 128, 0, 45, 198, 192, 0, 45, 198, 192 ])), MP4.box(MP4.types.pasp, new Uint8Array([ hSpacing >> 24, hSpacing >> 16 & 255, hSpacing >> 8 & 255, hSpacing & 255, vSpacing >> 24, vSpacing >> 16 & 255, vSpacing >> 8 & 255, vSpacing & 255 ]))); } }; MP4.types = void 0; MP4.HDLR_TYPES = void 0; MP4.STTS = void 0; MP4.STSC = void 0; MP4.STCO = void 0; MP4.STSZ = void 0; MP4.VMHD = void 0; MP4.SMHD = void 0; MP4.STSD = void 0; MP4.FTYP = void 0; MP4.DINF = void 0; var MPEG_TS_CLOCK_FREQ_HZ = 9e4; function toTimescaleFromBase(baseTime, destScale, srcBase = 1, round = false) { const result = baseTime * destScale * srcBase; return round ? Math.round(result) : result; } function toTimescaleFromScale(baseTime, destScale, srcScale = 1, round = false) { return toTimescaleFromBase(baseTime, destScale, 1 / srcScale, round); } function toMsFromMpegTsClock(baseTime, round = false) { return toTimescaleFromBase(baseTime, 1e3, 1 / MPEG_TS_CLOCK_FREQ_HZ, round); } function toMpegTsClockFromTimescale(baseTime, srcScale = 1) { return toTimescaleFromBase(baseTime, MPEG_TS_CLOCK_FREQ_HZ, 1 / srcScale); } function timestampToString(timestamp) { const { baseTime, timescale, trackId } = timestamp; return `${baseTime / timescale} (${baseTime}/${timescale}) trackId: ${trackId}`; } var MAX_SILENT_FRAME_DURATION = 10 * 1e3; var AAC_SAMPLES_PER_FRAME = 1024; var MPEG_AUDIO_SAMPLE_PER_FRAME = 1152; var AC3_SAMPLES_PER_FRAME = 1536; var chromeVersion = null; var safariWebkitVersion = null; function createMp4Sample(isKeyframe, duration, size, cts) { return { duration, size, cts, flags: { isLeading: 0, isDependedOn: 0, hasRedundancy: 0, degradPrio: 0, dependsOn: isKeyframe ? 2 : 1, isNonSync: isKeyframe ? 0 : 1 } }; } var MP4Remuxer = class extends Logger { constructor(observer, config, typeSupported, logger) { super("mp4-remuxer", logger); this.observer = void 0; this.config = void 0; this.typeSupported = void 0; this.ISGenerated = false; this._initPTS = null; this._initDTS = null; this.nextVideoTs = null; this.nextAudioTs = null; this.videoSampleDuration = null; this.isAudioContiguous = false; this.isVideoContiguous = false; this.videoTrackConfig = void 0; this.observer = observer; this.config = config; this.typeSupported = typeSupported; this.ISGenerated = false; if (chromeVersion === null) { const result = (navigator.userAgent || "").match(/Chrome\/(\d+)/i); chromeVersion = result ? parseInt(result[1]) : 0; } if (safariWebkitVersion === null) { const result = navigator.userAgent.match(/Safari\/(\d+)/i); safariWebkitVersion = result ? parseInt(result[1]) : 0; } } destroy() { this.config = this.videoTrackConfig = this._initPTS = this._initDTS = null; } resetTimeStamp(defaultTimeStamp) { const initPTS = this._initPTS; if (!initPTS || !defaultTimeStamp || defaultTimeStamp.trackId !== initPTS.trackId || defaultTimeStamp.baseTime !== initPTS.baseTime || defaultTimeStamp.timescale !== initPTS.timescale) this.log(`Reset initPTS: ${initPTS ? timestampToString(initPTS) : initPTS} > ${defaultTimeStamp ? timestampToString(defaultTimeStamp) : defaultTimeStamp}`); this._initPTS = this._initDTS = defaultTimeStamp; } resetNextTimestamp() { this.log("reset next timestamp"); this.isVideoContiguous = false; this.isAudioContiguous = false; } resetInitSegment() { this.log("ISGenerated flag reset"); this.ISGenerated = false; this.videoTrackConfig = void 0; } getVideoStartPts(videoSamples) { let rolloverDetected = false; const firstPts = videoSamples[0].pts; const startPTS = videoSamples.reduce((minPTS, sample) => { let pts = sample.pts; let delta = pts - minPTS; if (delta < -4294967296) { rolloverDetected = true; pts = normalizePts(pts, firstPts); delta = pts - minPTS; } if (delta > 0) return minPTS; return pts; }, firstPts); if (rolloverDetected) this.debug("PTS rollover detected"); return startPTS; } remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, flush, playlistType) { let video; let audio; let initSegment; let text; let id3; let independent; let audioTimeOffset = timeOffset; let videoTimeOffset = timeOffset; const hasAudio = audioTrack.pid > -1; const hasVideo = videoTrack.pid > -1; const length = videoTrack.samples.length; const enoughAudioSamples = audioTrack.samples.length > 0; const enoughVideoSamples = flush && length > 0 || length > 1; if ((!hasAudio || enoughAudioSamples) && (!hasVideo || enoughVideoSamples) || this.ISGenerated || flush) { if (this.ISGenerated) { var _videoTrack$pixelRati, _config$pixelRatio, _videoTrack$pixelRati2, _config$pixelRatio2; const config = this.videoTrackConfig; if (config && (videoTrack.width !== config.width || videoTrack.height !== config.height || ((_videoTrack$pixelRati = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati[0]) !== ((_config$pixelRatio = config.pixelRatio) == null ? void 0 : _config$pixelRatio[0]) || ((_videoTrack$pixelRati2 = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati2[1]) !== ((_config$pixelRatio2 = config.pixelRatio) == null ? void 0 : _config$pixelRatio2[1])) || !config && enoughVideoSamples || this.nextAudioTs === null && enoughAudioSamples) this.resetInitSegment(); } if (!this.ISGenerated) initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset); const isVideoContiguous = this.isVideoContiguous; let firstKeyFrameIndex = -1; let firstKeyFramePTS; if (enoughVideoSamples) { firstKeyFrameIndex = findKeyframeIndex(videoTrack.samples); if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) { independent = true; if (firstKeyFrameIndex > 0) { this.warn(`Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`); const startPTS = this.getVideoStartPts(videoTrack.samples); videoTrack.samples = videoTrack.samples.slice(firstKeyFrameIndex); videoTrack.dropped += firstKeyFrameIndex; videoTimeOffset += (videoTrack.samples[0].pts - startPTS) / videoTrack.inputTimeScale; firstKeyFramePTS = videoTimeOffset; } else if (firstKeyFrameIndex === -1) { this.warn(`No keyframe found out of ${length} video samples`); independent = false; } } } if (this.ISGenerated) { if (enoughAudioSamples && enoughVideoSamples) { const startPTS = this.getVideoStartPts(videoTrack.samples); const audiovideoTimestampDelta = (normalizePts(audioTrack.samples[0].pts, startPTS) - startPTS) / videoTrack.inputTimeScale; audioTimeOffset += Math.max(0, audiovideoTimestampDelta); videoTimeOffset += Math.max(0, -audiovideoTimestampDelta); } if (enoughAudioSamples) { if (!audioTrack.samplerate) { this.warn("regenerate InitSegment as audio detected"); initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset); } audio = this.remuxAudio(audioTrack, audioTimeOffset, this.isAudioContiguous, accurateTimeOffset, hasVideo || enoughVideoSamples || playlistType === PlaylistLevelType.AUDIO ? videoTimeOffset : void 0); if (enoughVideoSamples) { const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0; if (!videoTrack.inputTimeScale) { this.warn("regenerate InitSegment as video detected"); initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset); } video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, audioTrackLength); } } else if (enoughVideoSamples) video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, 0); if (video) { video.firstKeyFrame = firstKeyFrameIndex; video.independent = firstKeyFrameIndex !== -1; video.firstKeyFramePTS = firstKeyFramePTS; } } } if (this.ISGenerated && this._initPTS && this._initDTS) { if (id3Track.samples.length) id3 = flushTextTrackMetadataCueSamples(id3Track, timeOffset, this._initPTS, this._initDTS); if (textTrack.samples.length) text = flushTextTrackUserdataCueSamples(textTrack, timeOffset, this._initPTS); } return { audio, video, initSegment, independent, text, id3 }; } computeInitPts(basetime, timescale, presentationTime, type) { const offset = Math.round(presentationTime * timescale); let timestamp = normalizePts(basetime, offset); if (timestamp < offset + timescale) { this.log(`Adjusting PTS for rollover in timeline near ${(offset - timestamp) / timescale} ${type}`); while (timestamp < offset + timescale) timestamp += 8589934592; } return timestamp - offset; } generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset) { const audioSamples = audioTrack.samples; const videoSamples = videoTrack.samples; const typeSupported = this.typeSupported; const tracks = {}; const _initPTS = this._initPTS; let computePTSDTS = !_initPTS || accurateTimeOffset; let container = "audio/mp4"; let initPTS; let initDTS; let timescale; let trackId = -1; if (computePTSDTS) initPTS = initDTS = Infinity; if (audioTrack.config && audioSamples.length) { audioTrack.timescale = audioTrack.samplerate; switch (audioTrack.segmentCodec) { case "mp3": if (typeSupported.mpeg) { container = "audio/mpeg"; audioTrack.codec = ""; } else if (typeSupported.mp3) audioTrack.codec = "mp3"; break; case "ac3": audioTrack.codec = "ac-3"; break; } tracks.audio = { id: "audio", container, codec: audioTrack.codec, initSegment: audioTrack.segmentCodec === "mp3" && typeSupported.mpeg ? new Uint8Array(0) : MP4.initSegment([audioTrack]), metadata: { channelCount: audioTrack.channelCount } }; if (computePTSDTS) { trackId = audioTrack.id; timescale = audioTrack.inputTimeScale; if (!_initPTS || timescale !== _initPTS.timescale) initPTS = initDTS = this.computeInitPts(audioSamples[0].pts, timescale, timeOffset, "audio"); else computePTSDTS = false; } } if (videoTrack.sps && videoTrack.pps && videoSamples.length) { videoTrack.timescale = videoTrack.inputTimeScale; tracks.video = { id: "main", container: "video/mp4", codec: videoTrack.codec, initSegment: MP4.initSegment([videoTrack]), metadata: { width: videoTrack.width, height: videoTrack.height } }; if (computePTSDTS) { trackId = videoTrack.id; timescale = videoTrack.inputTimeScale; if (!_initPTS || timescale !== _initPTS.timescale) { const basePTS = this.getVideoStartPts(videoSamples); const baseDTS = normalizePts(videoSamples[0].dts, basePTS); const videoInitDTS = this.computeInitPts(baseDTS, timescale, timeOffset, "video"); const videoInitPTS = this.computeInitPts(basePTS, timescale, timeOffset, "video"); initDTS = Math.min(initDTS, videoInitDTS); initPTS = Math.min(initPTS, videoInitPTS); } else computePTSDTS = false; } this.videoTrackConfig = { width: videoTrack.width, height: videoTrack.height, pixelRatio: videoTrack.pixelRatio }; } if (Object.keys(tracks).length) { this.ISGenerated = true; if (computePTSDTS) { if (_initPTS) this.warn(`Timestamps at playlist time: ${accurateTimeOffset ? "" : "~"}${timeOffset} ${initPTS / timescale} != initPTS: ${_initPTS.baseTime / _initPTS.timescale} (${_initPTS.baseTime}/${_initPTS.timescale}) trackId: ${_initPTS.trackId}`); this.log(`Found initPTS at playlist time: ${timeOffset} offset: ${initPTS / timescale} (${initPTS}/${timescale}) trackId: ${trackId}`); this._initPTS = { baseTime: initPTS, timescale, trackId }; this._initDTS = { baseTime: initDTS, timescale, trackId }; } else initPTS = timescale = void 0; return { tracks, initPTS, timescale, trackId }; } } remuxVideo(track, timeOffset, contiguous, audioTrackLength) { const timeScale = track.inputTimeScale; const inputSamples = track.samples; const outputSamples = []; const nbSamples = inputSamples.length; const initPTS = this._initPTS; const initTime = initPTS.baseTime * timeScale / initPTS.timescale; let nextVideoTs = this.nextVideoTs; let offset = 8; let mp4SampleDuration = this.videoSampleDuration; let firstDTS; let lastDTS; let minPTS = Number.POSITIVE_INFINITY; let maxPTS = Number.NEGATIVE_INFINITY; let sortSamples = false; if (!contiguous || nextVideoTs === null) { const pts = initTime + timeOffset * timeScale; const cts = inputSamples[0].pts - normalizePts(inputSamples[0].dts, inputSamples[0].pts); if (chromeVersion && nextVideoTs !== null && Math.abs(pts - cts - (nextVideoTs + initTime)) < 15e3) contiguous = true; else nextVideoTs = pts - cts - initTime; } const nextVideoPts = nextVideoTs + initTime; for (let i = 0; i < nbSamples; i++) { const sample = inputSamples[i]; sample.pts = normalizePts(sample.pts, nextVideoPts); sample.dts = normalizePts(sample.dts, nextVideoPts); if (sample.dts < inputSamples[i > 0 ? i - 1 : i].dts) sortSamples = true; } if (sortSamples) inputSamples.sort(function(a, b) { const deltadts = a.dts - b.dts; const deltapts = a.pts - b.pts; return deltadts || deltapts; }); firstDTS = inputSamples[0].dts; lastDTS = inputSamples[inputSamples.length - 1].dts; const inputDuration = lastDTS - firstDTS; const averageSampleDuration = inputDuration ? Math.round(inputDuration / (nbSamples - 1)) : mp4SampleDuration || track.inputTimeScale / 30; if (contiguous) { const delta = firstDTS - nextVideoPts; const foundHole = delta > averageSampleDuration; const foundOverlap = delta < -1; if (foundHole || foundOverlap) { if (foundHole) this.warn(`${(track.segmentCodec || "").toUpperCase()}: ${toMsFromMpegTsClock(delta, true)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(3)}`); else this.warn(`${(track.segmentCodec || "").toUpperCase()}: ${toMsFromMpegTsClock(-delta, true)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(3)}`); if (!foundOverlap || nextVideoPts >= inputSamples[0].pts || chromeVersion) { firstDTS = nextVideoPts; const firstPTS = inputSamples[0].pts - delta; if (foundHole) { inputSamples[0].dts = firstDTS; inputSamples[0].pts = firstPTS; } else { let isPTSOrderRetained = true; for (let i = 0; i < inputSamples.length; i++) { if (inputSamples[i].dts > firstPTS && isPTSOrderRetained) break; const prevPTS = inputSamples[i].pts; inputSamples[i].dts -= delta; inputSamples[i].pts -= delta; if (i < inputSamples.length - 1) { const nextSamplePTS = inputSamples[i + 1].pts; isPTSOrderRetained = nextSamplePTS <= inputSamples[i].pts == nextSamplePTS <= prevPTS; } } } this.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`); } } } firstDTS = Math.max(0, firstDTS); let nbNalu = 0; let naluLen = 0; let dtsStep = firstDTS; for (let i = 0; i < nbSamples; i++) { const sample = inputSamples[i]; const units = sample.units; const nbUnits = units.length; let sampleLen = 0; for (let j = 0; j < nbUnits; j++) sampleLen += units[j].data.length; naluLen += sampleLen; nbNalu += nbUnits; sample.length = sampleLen; if (sample.dts < dtsStep) { sample.dts = dtsStep; dtsStep += averageSampleDuration / 4 | 0 || 1; } else dtsStep = sample.dts; minPTS = Math.min(sample.pts, minPTS); maxPTS = Math.max(sample.pts, maxPTS); } lastDTS = inputSamples[nbSamples - 1].dts; const mdatSize = naluLen + 4 * nbNalu + 8; let mdat; try { mdat = new Uint8Array(mdatSize); } catch (err) { this.observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MUX_ERROR, details: ErrorDetails.REMUX_ALLOC_ERROR, fatal: false, error: err, bytes: mdatSize, reason: `fail allocating video mdat ${mdatSize}` }); return; } const view = new DataView(mdat.buffer); view.setUint32(0, mdatSize); mdat.set(MP4.types.mdat, 4); let stretchedLastFrame = false; let minDtsDelta = Number.POSITIVE_INFINITY; let minPtsDelta = Number.POSITIVE_INFINITY; let maxDtsDelta = Number.NEGATIVE_INFINITY; let maxPtsDelta = Number.NEGATIVE_INFINITY; for (let i = 0; i < nbSamples; i++) { const VideoSample = inputSamples[i]; const VideoSampleUnits = VideoSample.units; let mp4SampleLength = 0; for (let j = 0, nbUnits = VideoSampleUnits.length; j < nbUnits; j++) { const unit = VideoSampleUnits[j]; const unitData = unit.data; const unitDataLen = unit.data.byteLength; view.setUint32(offset, unitDataLen); offset += 4; mdat.set(unitData, offset); offset += unitDataLen; mp4SampleLength += 4 + unitDataLen; } let ptsDelta; if (i < nbSamples - 1) { mp4SampleDuration = inputSamples[i + 1].dts - VideoSample.dts; ptsDelta = inputSamples[i + 1].pts - VideoSample.pts; } else { const config = this.config; const lastFrameDuration = i > 0 ? VideoSample.dts - inputSamples[i - 1].dts : averageSampleDuration; ptsDelta = i > 0 ? VideoSample.pts - inputSamples[i - 1].pts : averageSampleDuration; if (config.stretchShortVideoTrack && this.nextAudioTs !== null) { const gapTolerance = Math.floor(config.maxBufferHole * timeScale); const deltaToFrameEnd = (audioTrackLength ? minPTS + audioTrackLength * timeScale : this.nextAudioTs + initTime) - VideoSample.pts; if (deltaToFrameEnd > gapTolerance) { mp4SampleDuration = deltaToFrameEnd - lastFrameDuration; if (mp4SampleDuration < 0) mp4SampleDuration = lastFrameDuration; else stretchedLastFrame = true; this.log(`It is approximately ${deltaToFrameEnd / 90} ms to the next segment; using duration ${mp4SampleDuration / 90} ms for the last video frame.`); } else mp4SampleDuration = lastFrameDuration; } else mp4SampleDuration = lastFrameDuration; } const compositionTimeOffset = Math.round(VideoSample.pts - VideoSample.dts); minDtsDelta = Math.min(minDtsDelta, mp4SampleDuration); maxDtsDelta = Math.max(maxDtsDelta, mp4SampleDuration); minPtsDelta = Math.min(minPtsDelta, ptsDelta); maxPtsDelta = Math.max(maxPtsDelta, ptsDelta); outputSamples.push(createMp4Sample(VideoSample.key, mp4SampleDuration, mp4SampleLength, compositionTimeOffset)); } if (outputSamples.length) { if (chromeVersion) { if (chromeVersion < 70) { const flags = outputSamples[0].flags; flags.dependsOn = 2; flags.isNonSync = 0; } } else if (safariWebkitVersion) { if (maxPtsDelta - minPtsDelta < maxDtsDelta - minDtsDelta && averageSampleDuration / maxDtsDelta < .025 && outputSamples[0].cts === 0) { this.warn("Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration."); let dts = firstDTS; for (let i = 0, len = outputSamples.length; i < len; i++) { const nextDts = dts + outputSamples[i].duration; const pts = dts + outputSamples[i].cts; if (i < len - 1) { const nextPts = nextDts + outputSamples[i + 1].cts; outputSamples[i].duration = nextPts - pts; } else outputSamples[i].duration = i ? outputSamples[i - 1].duration : averageSampleDuration; outputSamples[i].cts = 0; dts = nextDts; } } } } mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration; const endDTS = lastDTS + mp4SampleDuration; this.nextVideoTs = nextVideoTs = endDTS - initTime; this.videoSampleDuration = mp4SampleDuration; this.isVideoContiguous = true; const data = { data1: MP4.moof(track.sequenceNumber++, firstDTS, _extends(track, { samples: outputSamples })), data2: mdat, startPTS: (minPTS - initTime) / timeScale, endPTS: (maxPTS + mp4SampleDuration - initTime) / timeScale, startDTS: (firstDTS - initTime) / timeScale, endDTS: nextVideoTs / timeScale, type: "video", hasAudio: false, hasVideo: true, nb: outputSamples.length, dropped: track.dropped }; track.samples = []; track.dropped = 0; return data; } getSamplesPerFrame(track) { switch (track.segmentCodec) { case "mp3": return MPEG_AUDIO_SAMPLE_PER_FRAME; case "ac3": return AC3_SAMPLES_PER_FRAME; default: return AAC_SAMPLES_PER_FRAME; } } remuxAudio(track, timeOffset, contiguous, accurateTimeOffset, videoTimeOffset) { const inputTimeScale = track.inputTimeScale; const scaleFactor = inputTimeScale / (track.samplerate ? track.samplerate : inputTimeScale); const mp4SampleDuration = this.getSamplesPerFrame(track); const inputSampleDuration = mp4SampleDuration * scaleFactor; const initPTS = this._initPTS; const rawMPEG = track.segmentCodec === "mp3" && this.typeSupported.mpeg; const outputSamples = []; const alignedWithVideo = videoTimeOffset !== void 0; let inputSamples = track.samples; let offset = rawMPEG ? 0 : 8; let nextAudioTs = this.nextAudioTs || -1; const initTime = initPTS.baseTime * inputTimeScale / initPTS.timescale; const timeOffsetMpegTS = initTime + timeOffset * inputTimeScale; this.isAudioContiguous = contiguous = contiguous || inputSamples.length && nextAudioTs > 0 && (accurateTimeOffset && Math.abs(timeOffsetMpegTS - (nextAudioTs + initTime)) < 9e3 || Math.abs(normalizePts(inputSamples[0].pts, timeOffsetMpegTS) - (nextAudioTs + initTime)) < 20 * inputSampleDuration); inputSamples.forEach(function(sample) { sample.pts = normalizePts(sample.pts, timeOffsetMpegTS); }); if (!contiguous || nextAudioTs < 0) { const sampleCount = inputSamples.length; inputSamples = inputSamples.filter((sample) => sample.pts >= 0); if (sampleCount !== inputSamples.length) this.warn(`Removed ${inputSamples.length - sampleCount} of ${sampleCount} samples (initPTS ${initTime} / ${inputTimeScale})`); if (!inputSamples.length) return; if (videoTimeOffset === 0) nextAudioTs = 0; else if (accurateTimeOffset && !alignedWithVideo) nextAudioTs = Math.max(0, timeOffsetMpegTS - initTime); else nextAudioTs = inputSamples[0].pts - initTime; } if (track.segmentCodec === "aac") { const maxAudioFramesDrift = this.config.maxAudioFramesDrift; for (let i = 0, nextPts = nextAudioTs + initTime; i < inputSamples.length; i++) { const sample = inputSamples[i]; const pts = sample.pts; const delta = pts - nextPts; const duration = Math.abs(1e3 * delta / inputTimeScale); if (delta <= -maxAudioFramesDrift * inputSampleDuration && alignedWithVideo) { if (i === 0) { this.warn(`Audio frame @ ${(pts / inputTimeScale).toFixed(3)}s overlaps marker by ${Math.round(1e3 * delta / inputTimeScale)} ms.`); this.nextAudioTs = nextAudioTs = pts - initTime; nextPts = pts; } } else if (delta >= maxAudioFramesDrift * inputSampleDuration && duration < MAX_SILENT_FRAME_DURATION && alignedWithVideo) { let missing = Math.round(delta / inputSampleDuration); nextPts = pts - missing * inputSampleDuration; while (nextPts < 0 && missing && inputSampleDuration) { missing--; nextPts += inputSampleDuration; } if (i === 0) this.nextAudioTs = nextAudioTs = nextPts - initTime; this.warn(`Injecting ${missing} audio frames @ ${((nextPts - initTime) / inputTimeScale).toFixed(3)}s due to ${Math.round(1e3 * delta / inputTimeScale)} ms gap.`); for (let j = 0; j < missing; j++) { let fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount); if (!fillFrame) { this.log("Unable to get silent frame for given audio codec; duplicating last frame instead."); fillFrame = sample.unit.subarray(); } inputSamples.splice(i, 0, { unit: fillFrame, pts: nextPts }); nextPts += inputSampleDuration; i++; } } sample.pts = nextPts; nextPts += inputSampleDuration; } } let firstPTS = null; let lastPTS = null; let mdat; let mdatSize = 0; let sampleLength = inputSamples.length; while (sampleLength--) mdatSize += inputSamples[sampleLength].unit.byteLength; for (let j = 0, _nbSamples = inputSamples.length; j < _nbSamples; j++) { const audioSample = inputSamples[j]; const unit = audioSample.unit; let pts = audioSample.pts; if (lastPTS !== null) { const prevSample = outputSamples[j - 1]; prevSample.duration = Math.round((pts - lastPTS) / scaleFactor); } else { if (contiguous && track.segmentCodec === "aac") pts = nextAudioTs + initTime; firstPTS = pts; if (mdatSize > 0) { mdatSize += offset; try { mdat = new Uint8Array(mdatSize); } catch (err) { this.observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MUX_ERROR, details: ErrorDetails.REMUX_ALLOC_ERROR, fatal: false, error: err, bytes: mdatSize, reason: `fail allocating audio mdat ${mdatSize}` }); return; } if (!rawMPEG) { new DataView(mdat.buffer).setUint32(0, mdatSize); mdat.set(MP4.types.mdat, 4); } } else return; } mdat.set(unit, offset); const unitLen = unit.byteLength; offset += unitLen; outputSamples.push(createMp4Sample(true, mp4SampleDuration, unitLen, 0)); lastPTS = pts; } const nbSamples = outputSamples.length; if (!nbSamples) return; const lastSample = outputSamples[outputSamples.length - 1]; nextAudioTs = lastPTS - initTime; this.nextAudioTs = nextAudioTs + scaleFactor * lastSample.duration; const moof = rawMPEG ? new Uint8Array(0) : MP4.moof(track.sequenceNumber++, firstPTS / scaleFactor, _extends({}, track, { samples: outputSamples })); track.samples = []; const start = (firstPTS - initTime) / inputTimeScale; const end = this.nextAudioTs / inputTimeScale; const audioData = { data1: moof, data2: mdat, startPTS: start, endPTS: end, startDTS: start, endDTS: end, type: "audio", hasAudio: true, hasVideo: false, nb: nbSamples }; this.isAudioContiguous = true; return audioData; } }; function normalizePts(value, reference) { let offset; if (reference === null) return value; if (reference < value) offset = -8589934592; else offset = 8589934592; while (Math.abs(value - reference) > 4294967296) value += offset; return value; } function findKeyframeIndex(samples) { for (let i = 0; i < samples.length; i++) if (samples[i].key) return i; return -1; } function flushTextTrackMetadataCueSamples(track, timeOffset, initPTS, initDTS) { const length = track.samples.length; if (!length) return; const inputTimeScale = track.inputTimeScale; for (let index = 0; index < length; index++) { const sample = track.samples[index]; sample.pts = normalizePts(sample.pts - initPTS.baseTime * inputTimeScale / initPTS.timescale, timeOffset * inputTimeScale) / inputTimeScale; sample.dts = normalizePts(sample.dts - initDTS.baseTime * inputTimeScale / initDTS.timescale, timeOffset * inputTimeScale) / inputTimeScale; } const samples = track.samples; track.samples = []; return { samples }; } function flushTextTrackUserdataCueSamples(track, timeOffset, initPTS) { const length = track.samples.length; if (!length) return; const inputTimeScale = track.inputTimeScale; for (let index = 0; index < length; index++) { const sample = track.samples[index]; sample.pts = normalizePts(sample.pts - initPTS.baseTime * inputTimeScale / initPTS.timescale, timeOffset * inputTimeScale) / inputTimeScale; } track.samples.sort((a, b) => a.pts - b.pts); const samples = track.samples; track.samples = []; return { samples }; } var PassThroughRemuxer = class extends Logger { constructor(observer, config, typeSupported, logger) { super("passthrough-remuxer", logger); this.emitInitSegment = false; this.audioCodec = void 0; this.videoCodec = void 0; this.initData = void 0; this.initPTS = null; this.initTracks = void 0; this.lastEndTime = null; this.isVideoContiguous = false; } destroy() {} resetTimeStamp(defaultInitPTS) { this.lastEndTime = null; const initPTS = this.initPTS; if (initPTS && defaultInitPTS) { if (initPTS.baseTime === defaultInitPTS.baseTime && initPTS.timescale === defaultInitPTS.timescale) return; } this.initPTS = defaultInitPTS; } resetNextTimestamp() { this.isVideoContiguous = false; this.lastEndTime = null; } resetInitSegment(initSegment, audioCodec, videoCodec, decryptdata) { this.audioCodec = audioCodec; this.videoCodec = videoCodec; this.generateInitSegment(initSegment, decryptdata); this.emitInitSegment = true; } generateInitSegment(initSegment, decryptdata) { let { audioCodec, videoCodec } = this; if (!(initSegment != null && initSegment.byteLength)) { this.initTracks = void 0; this.initData = void 0; return; } const { audio, video } = this.initData = parseInitSegment(initSegment); if (decryptdata) patchEncyptionData(initSegment, decryptdata); else { const eitherTrack = audio || video; if (eitherTrack != null && eitherTrack.encrypted) this.warn(`Init segment with encrypted track with has no key ("${eitherTrack.codec}")!`); } if (audio) audioCodec = getParsedTrackCodec(audio, ElementaryStreamTypes.AUDIO, this); if (video) videoCodec = getParsedTrackCodec(video, ElementaryStreamTypes.VIDEO, this); const tracks = {}; if (audio && video) tracks.audiovideo = { container: "video/mp4", codec: audioCodec + "," + videoCodec, supplemental: video.supplemental, encrypted: video.encrypted, initSegment, id: "main" }; else if (audio) tracks.audio = { container: "audio/mp4", codec: audioCodec, encrypted: audio.encrypted, initSegment, id: "audio" }; else if (video) tracks.video = { container: "video/mp4", codec: videoCodec, supplemental: video.supplemental, encrypted: video.encrypted, initSegment, id: "main" }; else this.warn("initSegment does not contain moov or trak boxes."); this.initTracks = tracks; } remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset) { var _initData, _initData2; let { initPTS, lastEndTime } = this; const result = { audio: void 0, video: void 0, text: textTrack, id3: id3Track, initSegment: void 0 }; if (!isFiniteNumber(lastEndTime)) lastEndTime = this.lastEndTime = timeOffset || 0; const data = videoTrack.samples; if (!data.length) return result; const initSegment = { initPTS: void 0, timescale: void 0, trackId: void 0 }; let initData = this.initData; if (!((_initData = initData) != null && _initData.length)) { this.generateInitSegment(data); initData = this.initData; } if (!((_initData2 = initData) != null && _initData2.length)) { this.warn("Failed to generate initSegment."); return result; } if (this.emitInitSegment) { initSegment.tracks = this.initTracks; this.emitInitSegment = false; } const trackSampleData = getSampleData(data, initData, this); const audioSampleTimestamps = initData.audio ? trackSampleData[initData.audio.id] : null; const videoSampleTimestamps = initData.video ? trackSampleData[initData.video.id] : null; const videoStartTime = toStartEndOrDefault(videoSampleTimestamps, Infinity); const audioStartTime = toStartEndOrDefault(audioSampleTimestamps, Infinity); const videoEndTime = toStartEndOrDefault(videoSampleTimestamps, 0, true); const audioEndTime = toStartEndOrDefault(audioSampleTimestamps, 0, true); let decodeTime = timeOffset; let duration = 0; const syncOnAudio = audioSampleTimestamps && (!videoSampleTimestamps || !initPTS && audioStartTime < videoStartTime || initPTS && initPTS.trackId === initData.audio.id); const baseOffsetSamples = syncOnAudio ? audioSampleTimestamps : videoSampleTimestamps; if (baseOffsetSamples) { const timescale = baseOffsetSamples.timescale; const baseTime = baseOffsetSamples.start - timeOffset * timescale; const trackId = syncOnAudio ? initData.audio.id : initData.video.id; decodeTime = baseOffsetSamples.start / timescale; duration = syncOnAudio ? audioEndTime - audioStartTime : videoEndTime - videoStartTime; if ((accurateTimeOffset || !initPTS) && (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) || timescale !== initPTS.timescale)) { if (initPTS) this.warn(`Timestamps at playlist time: ${accurateTimeOffset ? "" : "~"}${timeOffset} ${baseTime / timescale} != initPTS: ${initPTS.baseTime / initPTS.timescale} (${initPTS.baseTime}/${initPTS.timescale}) trackId: ${initPTS.trackId}`); this.log(`Found initPTS at playlist time: ${timeOffset} offset: ${decodeTime - timeOffset} (${baseTime}/${timescale}) trackId: ${trackId}`); initPTS = null; initSegment.initPTS = baseTime; initSegment.timescale = timescale; initSegment.trackId = trackId; } } else this.warn(`No audio or video samples found for initPTS at playlist time: ${timeOffset}`); if (!initPTS) { if (!initSegment.timescale || initSegment.trackId === void 0 || initSegment.initPTS === void 0) { this.warn("Could not set initPTS"); initSegment.initPTS = decodeTime; initSegment.timescale = 1; initSegment.trackId = -1; } this.initPTS = initPTS = { baseTime: initSegment.initPTS, timescale: initSegment.timescale, trackId: initSegment.trackId }; } else { initSegment.initPTS = initPTS.baseTime; initSegment.timescale = initPTS.timescale; initSegment.trackId = initPTS.trackId; } const startTime = decodeTime - initPTS.baseTime / initPTS.timescale; const endTime = startTime + duration; if (duration > 0) this.lastEndTime = endTime; else { this.warn("Duration parsed from mp4 should be greater than zero"); this.resetNextTimestamp(); } const hasAudio = !!initData.audio; const hasVideo = !!initData.video; let type = ""; if (hasAudio) type += "audio"; if (hasVideo) type += "video"; const encrypted = (initData.audio ? initData.audio.encrypted : false) || (initData.video ? initData.video.encrypted : false); const track = { data1: data, startPTS: startTime, startDTS: startTime, endPTS: endTime, endDTS: endTime, type, hasAudio, hasVideo, nb: 1, dropped: 0, encrypted }; result.audio = hasAudio && !hasVideo ? track : void 0; result.video = hasVideo ? track : void 0; const videoSampleCount = videoSampleTimestamps == null ? void 0 : videoSampleTimestamps.sampleCount; if (videoSampleCount) { const firstKeyFrame = videoSampleTimestamps.keyFrameIndex; const independent = firstKeyFrame !== -1; track.nb = videoSampleCount; track.dropped = firstKeyFrame === 0 || this.isVideoContiguous ? 0 : independent ? firstKeyFrame : videoSampleCount; track.independent = independent; track.firstKeyFrame = firstKeyFrame; if (independent && videoSampleTimestamps.keyFrameStart) track.firstKeyFramePTS = (videoSampleTimestamps.keyFrameStart - initPTS.baseTime) / initPTS.timescale; if (!this.isVideoContiguous) result.independent = independent; this.isVideoContiguous || (this.isVideoContiguous = independent); if (track.dropped) this.warn(`fmp4 does not start with IDR: firstIDR ${firstKeyFrame}/${videoSampleCount} dropped: ${track.dropped} start: ${track.firstKeyFramePTS || "NA"}`); } result.initSegment = initSegment; result.id3 = flushTextTrackMetadataCueSamples(id3Track, timeOffset, initPTS, initPTS); if (textTrack.samples.length) result.text = flushTextTrackUserdataCueSamples(textTrack, timeOffset, initPTS); return result; } }; function toStartEndOrDefault(trackTimes, defaultValue, end = false) { return (trackTimes == null ? void 0 : trackTimes.start) !== void 0 ? (trackTimes.start + (end ? trackTimes.duration : 0)) / trackTimes.timescale : defaultValue; } function isInvalidInitPts(initPTS, startDTS, timeOffset, duration) { if (initPTS === null) return true; const minDuration = Math.max(duration, 1); const startTime = startDTS - initPTS.baseTime / initPTS.timescale; return Math.abs(startTime - timeOffset) > minDuration; } function getParsedTrackCodec(track, type, logger) { const parsedCodec = track.codec; if (parsedCodec && parsedCodec.length > 4) return parsedCodec; if (type === ElementaryStreamTypes.AUDIO) { if (parsedCodec === "ec-3" || parsedCodec === "ac-3" || parsedCodec === "alac") return parsedCodec; if (parsedCodec === "fLaC" || parsedCodec === "Opus") return getCodecCompatibleName(parsedCodec, false); logger.warn(`Unhandled audio codec "${parsedCodec}" in mp4 MAP`); return parsedCodec || "mp4a"; } logger.warn(`Unhandled video codec "${parsedCodec}" in mp4 MAP`); return parsedCodec || "avc1"; } var now; try { now = self.performance.now.bind(self.performance); } catch (err) { now = Date.now; } var muxConfig = [ { demux: MP4Demuxer, remux: PassThroughRemuxer }, { demux: TSDemuxer, remux: MP4Remuxer }, { demux: AACDemuxer, remux: MP4Remuxer }, { demux: MP3Demuxer, remux: MP4Remuxer } ]; muxConfig.splice(2, 0, { demux: AC3Demuxer, remux: MP4Remuxer }); var Transmuxer = class { constructor(observer, typeSupported, config, vendor, id, logger) { this.asyncResult = false; this.logger = void 0; this.observer = void 0; this.typeSupported = void 0; this.config = void 0; this.id = void 0; this.demuxer = void 0; this.remuxer = void 0; this.decrypter = void 0; this.probe = void 0; this.decryptionPromise = null; this.transmuxConfig = void 0; this.currentTransmuxState = void 0; this.observer = observer; this.typeSupported = typeSupported; this.config = config; this.id = id; this.logger = logger; } configure(transmuxConfig) { this.transmuxConfig = transmuxConfig; if (this.decrypter) this.decrypter.reset(); } push(data, decryptdata, chunkMeta, state) { const stats = chunkMeta.transmuxing; stats.executeStart = now(); let uintData = new Uint8Array(data); const { currentTransmuxState, transmuxConfig } = this; if (state) this.currentTransmuxState = state; const { contiguous, discontinuity, trackSwitch, accurateTimeOffset, timeOffset, initSegmentChange } = state || currentTransmuxState; const { audioCodec, videoCodec, defaultInitPts, duration, initSegmentData } = transmuxConfig; const keyData = getEncryptionType(uintData, decryptdata); if (keyData && isFullSegmentEncryption(keyData.method)) { const decrypter = this.getDecrypter(); const aesMode = getAesModeFromFullSegmentMethod(keyData.method); if (decrypter.isSync()) { let decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode); if (chunkMeta.part > -1) { const _data = decrypter.flush(); decryptedData = _data ? _data.buffer : _data; } if (!decryptedData) { stats.executeEnd = now(); return emptyResult(chunkMeta); } uintData = new Uint8Array(decryptedData); } else { this.asyncResult = true; this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then((decryptedData) => { const result = this.push(decryptedData, null, chunkMeta); this.decryptionPromise = null; return result; }); return this.decryptionPromise; } } const resetMuxers = this.needsProbing(discontinuity, trackSwitch); if (resetMuxers) { const error = this.configureTransmuxer(uintData); if (error) { this.logger.warn(`[transmuxer] ${error.message}`); this.observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, error, reason: error.message }); stats.executeEnd = now(); return emptyResult(chunkMeta); } } if (discontinuity || trackSwitch || initSegmentChange || resetMuxers) this.resetInitSegment(initSegmentData, audioCodec, videoCodec, duration, decryptdata); if (discontinuity || initSegmentChange || resetMuxers) this.resetInitialTimestamp(defaultInitPts); if (!contiguous) this.resetContiguity(); const result = this.transmux(uintData, keyData, timeOffset, accurateTimeOffset, chunkMeta); this.asyncResult = isPromise(result); const currentState = this.currentTransmuxState; currentState.contiguous = true; currentState.discontinuity = false; currentState.trackSwitch = false; stats.executeEnd = now(); return result; } flush(chunkMeta) { const stats = chunkMeta.transmuxing; stats.executeStart = now(); const { decrypter, currentTransmuxState, decryptionPromise } = this; if (decryptionPromise) { this.asyncResult = true; return decryptionPromise.then(() => { return this.flush(chunkMeta); }); } const transmuxResults = []; const { timeOffset } = currentTransmuxState; if (decrypter) { const decryptedData = decrypter.flush(); if (decryptedData) transmuxResults.push(this.push(decryptedData.buffer, null, chunkMeta)); } const { demuxer, remuxer } = this; if (!demuxer || !remuxer) { stats.executeEnd = now(); const emptyResults = [emptyResult(chunkMeta)]; if (this.asyncResult) return Promise.resolve(emptyResults); return emptyResults; } const demuxResultOrPromise = demuxer.flush(timeOffset); if (isPromise(demuxResultOrPromise)) { this.asyncResult = true; return demuxResultOrPromise.then((demuxResult) => { this.flushRemux(transmuxResults, demuxResult, chunkMeta); return transmuxResults; }); } this.flushRemux(transmuxResults, demuxResultOrPromise, chunkMeta); if (this.asyncResult) return Promise.resolve(transmuxResults); return transmuxResults; } flushRemux(transmuxResults, demuxResult, chunkMeta) { const { audioTrack, videoTrack, id3Track, textTrack } = demuxResult; const { accurateTimeOffset, timeOffset } = this.currentTransmuxState; this.logger.log(`[transmuxer.ts]: Flushed ${this.id} sn: ${chunkMeta.sn}${chunkMeta.part > -1 ? " part: " + chunkMeta.part : ""} of ${this.id === PlaylistLevelType.MAIN ? "level" : "track"} ${chunkMeta.level}`); const remuxResult = this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, true, this.id); transmuxResults.push({ remuxResult, chunkMeta }); chunkMeta.transmuxing.executeEnd = now(); } resetInitialTimestamp(defaultInitPts) { const { demuxer, remuxer } = this; if (!demuxer || !remuxer) return; demuxer.resetTimeStamp(defaultInitPts); remuxer.resetTimeStamp(defaultInitPts); } resetContiguity() { const { demuxer, remuxer } = this; if (!demuxer || !remuxer) return; demuxer.resetContiguity(); remuxer.resetNextTimestamp(); } resetInitSegment(initSegmentData, audioCodec, videoCodec, trackDuration, decryptdata) { const { demuxer, remuxer } = this; if (!demuxer || !remuxer) return; demuxer.resetInitSegment(initSegmentData, audioCodec, videoCodec, trackDuration); remuxer.resetInitSegment(initSegmentData, audioCodec, videoCodec, decryptdata); } destroy() { if (this.demuxer) { this.demuxer.destroy(); this.demuxer = void 0; } if (this.remuxer) { this.remuxer.destroy(); this.remuxer = void 0; } } transmux(data, keyData, timeOffset, accurateTimeOffset, chunkMeta) { let result; if (keyData && keyData.method === "SAMPLE-AES") result = this.transmuxSampleAes(data, keyData, timeOffset, accurateTimeOffset, chunkMeta); else result = this.transmuxUnencrypted(data, timeOffset, accurateTimeOffset, chunkMeta); return result; } transmuxUnencrypted(data, timeOffset, accurateTimeOffset, chunkMeta) { const { audioTrack, videoTrack, id3Track, textTrack } = this.demuxer.demux(data, timeOffset, false, !this.config.progressive); return { remuxResult: this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, false, this.id), chunkMeta }; } transmuxSampleAes(data, decryptData, timeOffset, accurateTimeOffset, chunkMeta) { return this.demuxer.demuxSampleAes(data, decryptData, timeOffset).then((demuxResult) => { return { remuxResult: this.remuxer.remux(demuxResult.audioTrack, demuxResult.videoTrack, demuxResult.id3Track, demuxResult.textTrack, timeOffset, accurateTimeOffset, false, this.id), chunkMeta }; }); } configureTransmuxer(data) { const { config, observer, typeSupported } = this; let mux; for (let i = 0, len = muxConfig.length; i < len; i++) { var _muxConfig$i$demux; if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data, this.logger)) { mux = muxConfig[i]; break; } } if (!mux) return /* @__PURE__ */ new Error("Failed to find demuxer by probing fragment data"); const demuxer = this.demuxer; const remuxer = this.remuxer; const Remuxer = mux.remux; const Demuxer = mux.demux; if (!remuxer || !(remuxer instanceof Remuxer)) this.remuxer = new Remuxer(observer, config, typeSupported, this.logger); if (!demuxer || !(demuxer instanceof Demuxer)) { this.demuxer = new Demuxer(observer, config, typeSupported, this.logger); this.probe = Demuxer.probe; } } needsProbing(discontinuity, trackSwitch) { return !this.demuxer || !this.remuxer || discontinuity || trackSwitch; } getDecrypter() { let decrypter = this.decrypter; if (!decrypter) decrypter = this.decrypter = new Decrypter(this.config); return decrypter; } }; function getEncryptionType(data, decryptData) { let encryptionType = null; if (data.byteLength > 0 && (decryptData == null ? void 0 : decryptData.key) != null && decryptData.iv !== null && decryptData.method != null) encryptionType = decryptData; return encryptionType; } var emptyResult = (chunkMeta) => ({ remuxResult: {}, chunkMeta }); function isPromise(p) { return "then" in p && p.then instanceof Function; } var TransmuxConfig = class { constructor(audioCodec, videoCodec, initSegmentData, duration, defaultInitPts) { this.audioCodec = void 0; this.videoCodec = void 0; this.initSegmentData = void 0; this.duration = void 0; this.defaultInitPts = void 0; this.audioCodec = audioCodec; this.videoCodec = videoCodec; this.initSegmentData = initSegmentData; this.duration = duration; this.defaultInitPts = defaultInitPts || null; } }; var TransmuxState = class { constructor(discontinuity, contiguous, accurateTimeOffset, trackSwitch, timeOffset, initSegmentChange) { this.discontinuity = void 0; this.contiguous = void 0; this.accurateTimeOffset = void 0; this.trackSwitch = void 0; this.timeOffset = void 0; this.initSegmentChange = void 0; this.discontinuity = discontinuity; this.contiguous = contiguous; this.accurateTimeOffset = accurateTimeOffset; this.trackSwitch = trackSwitch; this.timeOffset = timeOffset; this.initSegmentChange = initSegmentChange; } }; var transmuxerInstanceCount = 0; var TransmuxerInterface = class { constructor(_hls, id, onTransmuxComplete, onFlush) { this.error = null; this.hls = void 0; this.id = void 0; this.instanceNo = transmuxerInstanceCount++; this.observer = void 0; this.frag = null; this.part = null; this.useWorker = void 0; this.workerContext = null; this.transmuxer = null; this.onTransmuxComplete = void 0; this.onFlush = void 0; this.onWorkerMessage = (event) => { const data = event.data; const hls = this.hls; if (!hls || !(data != null && data.event) || data.instanceNo !== this.instanceNo) return; switch (data.event) { case "init": { var _this$workerContext; const objectURL = (_this$workerContext = this.workerContext) == null ? void 0 : _this$workerContext.objectURL; if (objectURL) self.URL.revokeObjectURL(objectURL); break; } case "transmuxComplete": this.handleTransmuxComplete(data.data); break; case "flush": this.onFlush(data.data); break; case "workerLog": if (hls.logger[data.data.logType]) hls.logger[data.data.logType](data.data.message); break; default: data.data = data.data || {}; data.data.frag = this.frag; data.data.part = this.part; data.data.id = this.id; hls.trigger(data.event, data.data); break; } }; this.onWorkerError = (event) => { if (!this.hls) return; const error = /* @__PURE__ */ new Error(`${event.message} (${event.filename}:${event.lineno})`); this.hls.config.enableWorker = false; this.hls.logger.warn(`Error in "${this.id}" Web Worker, fallback to inline`); this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.INTERNAL_EXCEPTION, fatal: false, event: "demuxerWorker", error }); }; const config = _hls.config; this.hls = _hls; this.id = id; this.useWorker = !!config.enableWorker; this.onTransmuxComplete = onTransmuxComplete; this.onFlush = onFlush; const forwardMessage = (ev, data) => { data = data || {}; data.frag = this.frag || void 0; if (ev === Events.ERROR) { data = data; data.parent = this.id; data.part = this.part; this.error = data.error; } this.hls.trigger(ev, data); }; this.observer = new EventEmitter(); this.observer.on(Events.FRAG_DECRYPTED, forwardMessage); this.observer.on(Events.ERROR, forwardMessage); const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource); if (this.useWorker && typeof Worker !== "undefined") { const logger = this.hls.logger; if (config.workerPath || hasUMDWorker()) { try { if (config.workerPath) { logger.log(`loading Web Worker ${config.workerPath} for "${id}"`); this.workerContext = loadWorker(config.workerPath); } else { logger.log(`injecting Web Worker for "${id}"`); this.workerContext = injectWorker(); } const { worker } = this.workerContext; worker.addEventListener("message", this.onWorkerMessage); worker.addEventListener("error", this.onWorkerError); worker.postMessage({ instanceNo: this.instanceNo, cmd: "init", typeSupported: m2tsTypeSupported, id, config: stringify(config) }); } catch (err) { logger.warn(`Error setting up "${id}" Web Worker, fallback to inline`, err); this.terminateWorker(); this.error = null; this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, "", id, _hls.logger); } return; } } this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, "", id, _hls.logger); } reset() { this.frag = null; this.part = null; if (this.workerContext) { const instanceNo = this.instanceNo; this.instanceNo = transmuxerInstanceCount++; const config = this.hls.config; const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource); this.workerContext.worker.postMessage({ instanceNo: this.instanceNo, cmd: "reset", resetNo: instanceNo, typeSupported: m2tsTypeSupported, id: this.id, config: stringify(config) }); } } terminateWorker() { if (this.workerContext) { const { worker } = this.workerContext; this.workerContext = null; worker.removeEventListener("message", this.onWorkerMessage); worker.removeEventListener("error", this.onWorkerError); removeWorkerFromStore(this.hls.config.workerPath); } } destroy() { if (this.workerContext) { this.terminateWorker(); this.onWorkerMessage = this.onWorkerError = null; } else { const transmuxer = this.transmuxer; if (transmuxer) { transmuxer.destroy(); this.transmuxer = null; } } const observer = this.observer; if (observer) observer.removeAllListeners(); this.frag = null; this.part = null; this.observer = null; this.hls = null; } push(data, initSegmentData, audioCodec, videoCodec, frag, part, duration, accurateTimeOffset, chunkMeta, defaultInitPTS) { var _frag$initSegment, _lastFrag$initSegment; chunkMeta.transmuxing.start = self.performance.now(); const { instanceNo, transmuxer } = this; const timeOffset = part ? part.start : frag.start; const decryptdata = frag.decryptdata; const lastFrag = this.frag; const discontinuity = !(lastFrag && frag.cc === lastFrag.cc); const trackSwitch = !(lastFrag && chunkMeta.level === lastFrag.level); const snDiff = lastFrag ? chunkMeta.sn - lastFrag.sn : -1; const partDiff = this.part ? chunkMeta.part - this.part.index : -1; const progressive = snDiff === 0 && chunkMeta.id > 1 && chunkMeta.id === (lastFrag == null ? void 0 : lastFrag.stats.chunkCount); const contiguous = !trackSwitch && (snDiff === 1 || snDiff === 0 && (partDiff === 1 || progressive && partDiff <= 0)); const now = self.performance.now(); if (trackSwitch || snDiff || frag.stats.parsing.start === 0) frag.stats.parsing.start = now; if (part && (partDiff || !contiguous)) part.stats.parsing.start = now; const initSegmentChange = !(lastFrag && ((_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.url) === ((_lastFrag$initSegment = lastFrag.initSegment) == null ? void 0 : _lastFrag$initSegment.url)); const state = new TransmuxState(discontinuity, contiguous, accurateTimeOffset, trackSwitch, timeOffset, initSegmentChange); if (!contiguous || discontinuity || initSegmentChange) { this.hls.logger.log(`[transmuxer-interface]: Starting new transmux session for ${frag.type} sn: ${chunkMeta.sn}${chunkMeta.part > -1 ? " part: " + chunkMeta.part : ""} ${this.id === PlaylistLevelType.MAIN ? "level" : "track"}: ${chunkMeta.level} id: ${chunkMeta.id} discontinuity: ${discontinuity} trackSwitch: ${trackSwitch} contiguous: ${contiguous} accurateTimeOffset: ${accurateTimeOffset} timeOffset: ${timeOffset} initSegmentChange: ${initSegmentChange}`); const config = new TransmuxConfig(audioCodec, videoCodec, initSegmentData, duration, defaultInitPTS); this.configureTransmuxer(config); } this.frag = frag; this.part = part; if (this.workerContext) this.workerContext.worker.postMessage({ instanceNo, cmd: "demux", data, decryptdata, chunkMeta, state }, data instanceof ArrayBuffer ? [data] : []); else if (transmuxer) { const transmuxResult = transmuxer.push(data, decryptdata, chunkMeta, state); if (isPromise(transmuxResult)) transmuxResult.then((data) => { this.handleTransmuxComplete(data); }).catch((error) => { this.transmuxerError(error, chunkMeta, "transmuxer-interface push error"); }); else this.handleTransmuxComplete(transmuxResult); } } flush(chunkMeta) { chunkMeta.transmuxing.start = self.performance.now(); const { instanceNo, transmuxer } = this; if (this.workerContext) this.workerContext.worker.postMessage({ instanceNo, cmd: "flush", chunkMeta }); else if (transmuxer) { const transmuxResult = transmuxer.flush(chunkMeta); if (isPromise(transmuxResult)) transmuxResult.then((data) => { this.handleFlushResult(data, chunkMeta); }).catch((error) => { this.transmuxerError(error, chunkMeta, "transmuxer-interface flush error"); }); else this.handleFlushResult(transmuxResult, chunkMeta); } } transmuxerError(error, chunkMeta, reason) { if (!this.hls) return; this.error = error; this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, chunkMeta, frag: this.frag || void 0, part: this.part || void 0, fatal: false, error, err: error, reason }); } handleFlushResult(results, chunkMeta) { results.forEach((result) => { this.handleTransmuxComplete(result); }); this.onFlush(chunkMeta); } configureTransmuxer(config) { const { instanceNo, transmuxer } = this; if (this.workerContext) this.workerContext.worker.postMessage({ instanceNo, cmd: "configure", config }); else if (transmuxer) transmuxer.configure(config); } handleTransmuxComplete(result) { result.chunkMeta.transmuxing.end = self.performance.now(); this.onTransmuxComplete(result); } }; var TICK_INTERVAL$3 = 100; var AudioStreamController = class extends BaseStreamController { constructor(hls, fragmentTracker, keyLoader) { super(hls, fragmentTracker, keyLoader, "audio-stream-controller", PlaylistLevelType.AUDIO); this.mainAnchor = null; this.mainFragLoading = null; this.audioOnly = false; this.bufferedTrack = null; this.switchingTrack = null; this.trackId = -1; this.waitingData = null; this.mainDetails = null; this.flushing = false; this.bufferFlushed = false; this.cachedTrackLoadedData = null; this.registerListeners(); } onHandlerDestroying() { this.unregisterListeners(); super.onHandlerDestroying(); this.resetItem(); } resetItem() { this.mainDetails = this.mainAnchor = this.mainFragLoading = this.bufferedTrack = this.switchingTrack = this.waitingData = this.cachedTrackLoadedData = null; } registerListeners() { super.registerListeners(); const { hls } = this; hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this); hls.on(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this); hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); hls.on(Events.BUFFER_RESET, this.onBufferReset, this); hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this); hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); hls.on(Events.FRAG_LOADING, this.onFragLoading, this); hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); } unregisterListeners() { const { hls } = this; if (!hls) return; super.unregisterListeners(); hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this); hls.off(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this); hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); hls.off(Events.BUFFER_RESET, this.onBufferReset, this); hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this); hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); hls.off(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); hls.off(Events.FRAG_LOADING, this.onFragLoading, this); hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); } onInitPtsFound(event, { frag, id, initPTS, timescale, trackId }) { if (id === PlaylistLevelType.MAIN) { const cc = frag.cc; const inFlightFrag = this.fragCurrent; this.initPTS[cc] = { baseTime: initPTS, timescale, trackId }; this.log(`InitPTS for cc: ${cc} found from main: ${initPTS / timescale} (${initPTS}/${timescale}) trackId: ${trackId}`); this.mainAnchor = frag; if (this.state === State.WAITING_INIT_PTS) { const waitingData = this.waitingData; if (!waitingData && !this.loadingParts || waitingData && waitingData.frag.cc !== cc) this.syncWithAnchor(frag, waitingData == null ? void 0 : waitingData.frag); } else if (!this.hls.hasEnoughToStart && inFlightFrag && inFlightFrag.cc !== cc) { inFlightFrag.abortRequests(); this.syncWithAnchor(frag, inFlightFrag); } else if (this.state === State.IDLE) this.tick(); } } getLoadPosition() { if (!this.startFragRequested && this.nextLoadPosition >= 0) return this.nextLoadPosition; return super.getLoadPosition(); } syncWithAnchor(mainAnchor, waitingToAppend) { var _this$mainFragLoading; const mainFragLoading = ((_this$mainFragLoading = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading.frag) || null; if (waitingToAppend) { if ((mainFragLoading == null ? void 0 : mainFragLoading.cc) === waitingToAppend.cc) return; } const targetDiscontinuity = (mainFragLoading || mainAnchor).cc; const syncFrag = findNearestWithCC(this.getLevelDetails(), targetDiscontinuity, this.getLoadPosition()); if (syncFrag) { this.log(`Syncing with main frag at ${syncFrag.start} cc ${syncFrag.cc}`); this.startFragRequested = false; this.nextLoadPosition = syncFrag.start; this.resetLoadingState(); if (this.state === State.IDLE) this.doTickIdle(); } } startLoad(startPosition, skipSeekToStartPosition) { if (!this.levels) { this.startPosition = startPosition; this.state = State.STOPPED; return; } const lastCurrentTime = this.lastCurrentTime; this.stopLoad(); this.setInterval(TICK_INTERVAL$3); if (lastCurrentTime > 0 && startPosition === -1) { this.log(`Override startPosition with lastCurrentTime @${lastCurrentTime.toFixed(3)}`); startPosition = lastCurrentTime; this.state = State.IDLE; } else this.state = State.WAITING_TRACK; this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset; this.startPosition = skipSeekToStartPosition ? -1 : startPosition; this.tick(); } doTick() { switch (this.state) { case State.IDLE: this.doTickIdle(); break; case State.WAITING_TRACK: { const { levels, trackId } = this; const currenTrack = levels == null ? void 0 : levels[trackId]; const details = currenTrack == null ? void 0 : currenTrack.details; if (details && !this.waitForLive(currenTrack)) { if (this.waitForCdnTuneIn(details)) break; this.state = State.WAITING_INIT_PTS; } break; } case State.FRAG_LOADING_WAITING_RETRY: this.checkRetryDate(); break; case State.WAITING_INIT_PTS: { const waitingData = this.waitingData; if (waitingData) { const { frag, part, cache, complete } = waitingData; const mainAnchor = this.mainAnchor; if (this.initPTS[frag.cc] !== void 0) { this.waitingData = null; this.state = State.FRAG_LOADING; const data = { frag, part, payload: cache.flush().buffer, networkDetails: null }; this._handleFragmentLoadProgress(data); if (complete) super._handleFragmentLoadComplete(data); } else if (mainAnchor && mainAnchor.cc !== waitingData.frag.cc) this.syncWithAnchor(mainAnchor, waitingData.frag); } else this.state = State.IDLE; } } this.onTickEnd(); } resetLoadingState() { const waitingData = this.waitingData; if (waitingData) { this.fragmentTracker.removeFragment(waitingData.frag); this.waitingData = null; } super.resetLoadingState(); } onTickEnd() { const { media } = this; if (!(media != null && media.readyState)) return; this.lastCurrentTime = media.currentTime; } doTickIdle() { var _this$mainFragLoading2; const { hls, levels, media, trackId } = this; const config = hls.config; if (!this.buffering || !media && !this.primaryPrefetch && (this.startFragRequested || !config.startFragPrefetch) || !(levels != null && levels[trackId])) return; const levelInfo = levels[trackId]; const trackDetails = levelInfo.details; if (!trackDetails || this.waitForLive(levelInfo) || this.waitForCdnTuneIn(trackDetails)) { this.state = State.WAITING_TRACK; this.startFragRequested = false; return; } const bufferable = this.mediaBuffer ? this.mediaBuffer : this.media; if (this.bufferFlushed && bufferable) { this.bufferFlushed = false; this.afterBufferFlushed(bufferable, ElementaryStreamTypes.AUDIO, PlaylistLevelType.AUDIO); } const bufferInfo = this.getFwdBufferInfo(bufferable, PlaylistLevelType.AUDIO); if (bufferInfo === null) return; if (!this.switchingTrack && this._streamEnded(bufferInfo, trackDetails)) { hls.trigger(Events.BUFFER_EOS, { type: "audio" }); this.state = State.ENDED; return; } const bufferLen = bufferInfo.len; const maxBufLen = hls.maxBufferLength; const fragments = trackDetails.fragments; const start = fragments[0].start; const loadPosition = this.getLoadPosition(); const targetBufferTime = this.flushing ? loadPosition : bufferInfo.end; if (this.switchingTrack && media) { const pos = loadPosition; if (trackDetails.PTSKnown && pos < start) { if (bufferInfo.end > start || bufferInfo.nextStart) { this.log("Alt audio track ahead of main track, seek to start of alt audio track"); media.currentTime = start + .05; } } } if (bufferLen >= maxBufLen && !this.switchingTrack && targetBufferTime < fragments[fragments.length - 1].start) return; let frag = this.getNextFragment(targetBufferTime, trackDetails); if (frag && this.isLoopLoading(frag, targetBufferTime)) frag = this.getNextFragmentLoopLoading(frag, trackDetails, bufferInfo, PlaylistLevelType.MAIN, maxBufLen); if (!frag) { this.bufferFlushed = true; return; } if (this.exceedsMaxBuffer(bufferInfo, maxBufLen, frag)) return; let mainFragLoading = ((_this$mainFragLoading2 = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading2.frag) || null; if (!this.audioOnly && this.startFragRequested && mainFragLoading && isMediaFragment(frag) && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) { if (this.fragmentTracker.getState(mainFragLoading) === FragmentState.OK) this.mainFragLoading = mainFragLoading = null; if (mainFragLoading && isMediaFragment(mainFragLoading)) { if (frag.start > mainFragLoading.end) { const mainFragAtPos = this.fragmentTracker.getFragAtPos(targetBufferTime, PlaylistLevelType.MAIN); if (mainFragAtPos && mainFragAtPos.end > mainFragLoading.end) { mainFragLoading = mainFragAtPos; this.mainFragLoading = { frag: mainFragAtPos, targetBufferTime: null }; } } if (frag.start > mainFragLoading.end) return; } } this.loadFragment(frag, levelInfo, targetBufferTime); } onMediaDetaching(event, data) { this.bufferFlushed = this.flushing = false; super.onMediaDetaching(event, data); } onAudioTracksUpdated(event, { audioTracks }) { this.resetTransmuxer(); this.levels = audioTracks.map((mediaPlaylist) => new Level(mediaPlaylist)); } onAudioTrackSwitching(event, data) { const altAudio = !!data.url; this.trackId = data.id; const { fragCurrent } = this; if (fragCurrent) { fragCurrent.abortRequests(); this.removeUnbufferedFrags(fragCurrent.start); } this.resetLoadingState(); if (altAudio) { this.switchingTrack = data; this.flushAudioIfNeeded(data); if (this.state !== State.STOPPED) { this.setInterval(TICK_INTERVAL$3); this.state = State.IDLE; this.tick(); } } else { this.resetTransmuxer(); this.switchingTrack = null; this.bufferedTrack = data; this.clearInterval(); } } onManifestLoading() { super.onManifestLoading(); this.bufferFlushed = this.flushing = this.audioOnly = false; this.resetItem(); this.trackId = -1; } onLevelLoaded(event, data) { this.mainDetails = data.details; const cachedTrackLoadedData = this.cachedTrackLoadedData; if (cachedTrackLoadedData) { this.cachedTrackLoadedData = null; this.onAudioTrackLoaded(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData); } } onAudioTrackLoaded(event, data) { var _trackLevel$details; const { levels } = this; const { details: newDetails, id: trackId, groupId, track } = data; if (!levels) { this.warn(`Audio tracks reset while loading track ${trackId} "${track.name}" of "${groupId}"`); return; } const mainDetails = this.mainDetails; if (!mainDetails || newDetails.endCC > mainDetails.endCC || mainDetails.expired) { this.cachedTrackLoadedData = data; if (this.state !== State.STOPPED) this.state = State.WAITING_TRACK; return; } this.cachedTrackLoadedData = null; this.log(`Audio track ${trackId} "${track.name}" of "${groupId}" loaded [${newDetails.startSN},${newDetails.endSN}]${newDetails.lastPartSn ? `[part-${newDetails.lastPartSn}-${newDetails.lastPartIndex}]` : ""},duration:${newDetails.totalduration}`); const trackLevel = levels[trackId]; let sliding = 0; if (newDetails.live || (_trackLevel$details = trackLevel.details) != null && _trackLevel$details.live) { this.checkLiveUpdate(newDetails); if (newDetails.deltaUpdateFailed) return; if (trackLevel.details) { var _this$levelLastLoaded; sliding = this.alignPlaylists(newDetails, trackLevel.details, (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details); } if (!newDetails.alignedSliding) { alignDiscontinuities(newDetails, mainDetails); if (!newDetails.alignedSliding) alignMediaPlaylistByPDT(newDetails, mainDetails); sliding = newDetails.fragmentStart; } } trackLevel.details = newDetails; this.levelLastLoaded = trackLevel; if (!this.startFragRequested) this.setStartPosition(mainDetails, sliding); this.hls.trigger(Events.AUDIO_TRACK_UPDATED, { details: newDetails, id: trackId, groupId: data.groupId }); if (this.state === State.WAITING_TRACK && !this.waitForCdnTuneIn(newDetails)) this.state = State.IDLE; this.tick(); } _handleFragmentLoadProgress(data) { var _frag$initSegment; const frag = data.frag; const { part, payload } = data; const { config, trackId, levels } = this; if (!levels) { this.warn(`Audio tracks were reset while fragment load was in progress. Fragment ${frag.sn} of level ${frag.level} will not be buffered`); return; } const track = levels[trackId]; if (!track) { this.warn("Audio track is undefined on fragment load progress"); return; } const details = track.details; if (!details) { this.warn("Audio track details undefined on fragment load progress"); this.removeUnbufferedFrags(frag.start); return; } const audioCodec = config.defaultAudioCodec || track.audioCodec || "mp4a.40.2"; let transmuxer = this.transmuxer; if (!transmuxer) transmuxer = this.transmuxer = new TransmuxerInterface(this.hls, PlaylistLevelType.AUDIO, this._handleTransmuxComplete.bind(this), this._handleTransmuxerFlush.bind(this)); const initPTS = this.initPTS[frag.cc]; const initSegmentData = (_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.data; if (initPTS !== void 0) { const accurateTimeOffset = false; const partIndex = part ? part.index : -1; const partial = partIndex !== -1; const chunkMeta = new ChunkMetadata(frag.level, frag.sn, frag.stats.chunkCount, payload.byteLength, partIndex, partial); transmuxer.push(payload, initSegmentData, audioCodec, "", frag, part, details.totalduration, accurateTimeOffset, chunkMeta, initPTS); } else { this.log(`Unknown video PTS for cc ${frag.cc}, waiting for video PTS before demuxing audio frag ${frag.sn} of [${details.startSN} ,${details.endSN}],track ${trackId}`); const { cache } = this.waitingData = this.waitingData || { frag, part, cache: new ChunkCache(), complete: false }; cache.push(new Uint8Array(payload)); if (this.state !== State.STOPPED) this.state = State.WAITING_INIT_PTS; } } _handleFragmentLoadComplete(fragLoadedData) { if (this.waitingData) { this.waitingData.complete = true; return; } super._handleFragmentLoadComplete(fragLoadedData); } onBufferReset() { this.mediaBuffer = null; } onBufferCreated(event, data) { this.bufferFlushed = this.flushing = false; const audioTrack = data.tracks.audio; if (audioTrack) this.mediaBuffer = audioTrack.buffer || null; } onFragLoading(event, data) { if (!this.audioOnly && data.frag.type === PlaylistLevelType.MAIN && isMediaFragment(data.frag)) { this.mainFragLoading = data; if (this.state === State.IDLE) this.tick(); } } onFragBuffered(event, data) { const { frag, part } = data; if (frag.type !== PlaylistLevelType.AUDIO) { if (!this.audioOnly && frag.type === PlaylistLevelType.MAIN && !frag.elementaryStreams.video && !frag.elementaryStreams.audiovideo) { this.audioOnly = true; this.mainFragLoading = null; } return; } if (this.fragContextChanged(frag)) { this.warn(`Fragment ${frag.sn}${part ? " p: " + part.index : ""} of level ${frag.level} finished buffering, but was aborted. state: ${this.state}, audioSwitch: ${this.switchingTrack ? this.switchingTrack.name : "false"}`); return; } if (isMediaFragment(frag)) { this.fragPrevious = frag; const track = this.switchingTrack; if (track) { this.bufferedTrack = track; this.switchingTrack = null; this.hls.trigger(Events.AUDIO_TRACK_SWITCHED, _objectSpread2({}, track)); } } this.fragBufferedComplete(frag, part); if (this.media) this.tick(); } onError(event, data) { var _data$context; if (data.fatal) { this.state = State.ERROR; return; } switch (data.details) { case ErrorDetails.FRAG_GAP: case ErrorDetails.FRAG_PARSING_ERROR: case ErrorDetails.FRAG_DECRYPT_ERROR: case ErrorDetails.FRAG_LOAD_ERROR: case ErrorDetails.FRAG_LOAD_TIMEOUT: case ErrorDetails.KEY_LOAD_ERROR: case ErrorDetails.KEY_LOAD_TIMEOUT: this.onFragmentOrKeyLoadError(PlaylistLevelType.AUDIO, data); break; case ErrorDetails.AUDIO_TRACK_LOAD_ERROR: case ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT: case ErrorDetails.LEVEL_PARSING_ERROR: if (!data.levelRetry && this.state === State.WAITING_TRACK && ((_data$context = data.context) == null ? void 0 : _data$context.type) === PlaylistContextType.AUDIO_TRACK) this.state = State.IDLE; break; case ErrorDetails.BUFFER_ADD_CODEC_ERROR: case ErrorDetails.BUFFER_APPEND_ERROR: if (data.parent !== "audio") return; if (!this.reduceLengthAndFlushBuffer(data)) this.resetLoadingState(); break; case ErrorDetails.BUFFER_FULL_ERROR: if (data.parent !== "audio") return; if (this.reduceLengthAndFlushBuffer(data)) { this.bufferedTrack = null; super.flushMainBuffer(0, Number.POSITIVE_INFINITY, "audio"); } break; case ErrorDetails.INTERNAL_EXCEPTION: this.recoverWorkerError(data); break; } } onBufferFlushing(event, { type }) { if (type !== ElementaryStreamTypes.VIDEO) this.flushing = true; } onBufferFlushed(event, { type }) { if (type !== ElementaryStreamTypes.VIDEO) { this.flushing = false; this.bufferFlushed = true; if (this.state === State.ENDED) this.state = State.IDLE; const mediaBuffer = this.mediaBuffer || this.media; if (mediaBuffer) { this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.AUDIO); this.tick(); } } } _handleTransmuxComplete(transmuxResult) { var _id3$samples; const id = "audio"; const { hls } = this; const { remuxResult, chunkMeta } = transmuxResult; const context = this.getCurrentContext(chunkMeta); if (!context) { this.resetWhenMissingContext(chunkMeta); return; } const { frag, part, level } = context; const { details } = level; const { audio, text, id3, initSegment } = remuxResult; if (this.fragContextChanged(frag) || !details) { this.fragmentTracker.removeFragment(frag); return; } this.state = State.PARSING; if (this.switchingTrack && audio) this.completeAudioSwitch(this.switchingTrack); if (initSegment != null && initSegment.tracks) { const mapFragment = frag.initSegment || frag; if (this.unhandledEncryptionError(initSegment, frag)) return; this._bufferInitSegment(level, initSegment.tracks, mapFragment, chunkMeta); hls.trigger(Events.FRAG_PARSING_INIT_SEGMENT, { frag: mapFragment, id, tracks: initSegment.tracks }); } if (audio) { const { startPTS, endPTS, startDTS, endDTS } = audio; if (part) part.elementaryStreams[ElementaryStreamTypes.AUDIO] = { startPTS, endPTS, startDTS, endDTS }; frag.setElementaryStreamInfo(ElementaryStreamTypes.AUDIO, startPTS, endPTS, startDTS, endDTS); this.bufferFragmentData(audio, frag, part, chunkMeta); } if (id3 != null && (_id3$samples = id3.samples) != null && _id3$samples.length) { const emittedID3 = _extends({ id, frag, details }, id3); hls.trigger(Events.FRAG_PARSING_METADATA, emittedID3); } if (text) { const emittedText = _extends({ id, frag, details }, text); hls.trigger(Events.FRAG_PARSING_USERDATA, emittedText); } } _bufferInitSegment(currentLevel, tracks, frag, chunkMeta) { if (this.state !== State.PARSING) return; if (tracks.video) delete tracks.video; if (tracks.audiovideo) delete tracks.audiovideo; if (!tracks.audio) return; const track = tracks.audio; track.id = PlaylistLevelType.AUDIO; const variantAudioCodecs = currentLevel.audioCodec; this.log(`Init audio buffer, container:${track.container}, codecs[level/parsed]=[${variantAudioCodecs}/${track.codec}]`); if (variantAudioCodecs && variantAudioCodecs.split(",").length === 1) track.levelCodec = variantAudioCodecs; this.hls.trigger(Events.BUFFER_CODECS, tracks); const initSegment = track.initSegment; if (initSegment != null && initSegment.byteLength) { const segment = { type: "audio", frag, part: null, chunkMeta, parent: frag.type, data: initSegment }; this.hls.trigger(Events.BUFFER_APPENDING, segment); } this.tickImmediate(); } loadFragment(frag, track, targetBufferTime) { const fragState = this.fragmentTracker.getState(frag); if (this.switchingTrack || fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) { var _track$details; if (!isMediaFragment(frag)) this._loadInitSegment(frag, track); else if ((_track$details = track.details) != null && _track$details.live && !this.initPTS[frag.cc]) { this.log(`Waiting for video PTS in continuity counter ${frag.cc} of live stream before loading audio fragment ${frag.sn} of level ${this.trackId}`); this.state = State.WAITING_INIT_PTS; const mainDetails = this.mainDetails; if (mainDetails && mainDetails.fragmentStart !== track.details.fragmentStart) alignMediaPlaylistByPDT(track.details, mainDetails); } else super.loadFragment(frag, track, targetBufferTime); } else this.clearTrackerIfNeeded(frag); } flushAudioIfNeeded(switchingTrack) { if (this.media && this.bufferedTrack) { const { name, lang, assocLang, characteristics, audioCodec, channels } = this.bufferedTrack; if (!matchesOption({ name, lang, assocLang, characteristics, audioCodec, channels }, switchingTrack, audioMatchPredicate)) if (useAlternateAudio(switchingTrack.url, this.hls)) { this.log("Switching audio track : flushing all audio"); super.flushMainBuffer(0, Number.POSITIVE_INFINITY, "audio"); this.bufferedTrack = null; } else this.bufferedTrack = switchingTrack; } } completeAudioSwitch(switchingTrack) { const { hls } = this; this.flushAudioIfNeeded(switchingTrack); this.bufferedTrack = switchingTrack; this.switchingTrack = null; hls.trigger(Events.AUDIO_TRACK_SWITCHED, _objectSpread2({}, switchingTrack)); } }; var BasePlaylistController = class extends Logger { constructor(hls, logPrefix) { super(logPrefix, hls.logger); this.hls = void 0; this.canLoad = false; this.timer = -1; this.hls = hls; } destroy() { this.clearTimer(); this.hls = this.log = this.warn = null; } clearTimer() { if (this.timer !== -1) { self.clearTimeout(this.timer); this.timer = -1; } } startLoad() { this.canLoad = true; this.loadPlaylist(); } stopLoad() { this.canLoad = false; this.clearTimer(); } switchParams(playlistUri, previous, current) { const renditionReports = previous == null ? void 0 : previous.renditionReports; if (renditionReports) { let foundIndex = -1; for (let i = 0; i < renditionReports.length; i++) { const attr = renditionReports[i]; let uri; try { uri = new self.URL(attr.URI, previous.url).href; } catch (error) { this.warn(`Could not construct new URL for Rendition Report: ${error}`); uri = attr.URI || ""; } if (uri === playlistUri) { foundIndex = i; break; } else if (uri === playlistUri.substring(0, uri.length)) foundIndex = i; } if (foundIndex !== -1) { const attr = renditionReports[foundIndex]; const msn = parseInt(attr["LAST-MSN"]) || previous.lastPartSn; let part = parseInt(attr["LAST-PART"]) || previous.lastPartIndex; if (this.hls.config.lowLatencyMode) { const currentGoal = Math.min(previous.age - previous.partTarget, previous.targetduration); if (part >= 0 && currentGoal > previous.partTarget) part += 1; } const skip = current && getSkipValue(current); return new HlsUrlParameters(msn, part >= 0 ? part : void 0, skip); } } } loadPlaylist(hlsUrlParameters) { this.clearTimer(); } loadingPlaylist(playlist, hlsUrlParameters) { this.clearTimer(); } shouldLoadPlaylist(playlist) { return this.canLoad && !!playlist && !!playlist.url && (!playlist.details || playlist.details.live); } getUrlWithDirectives(uri, hlsUrlParameters) { if (hlsUrlParameters) try { return hlsUrlParameters.addDirectives(uri); } catch (error) { this.warn(`Could not construct new URL with HLS Delivery Directives: ${error}`); } return uri; } playlistLoaded(index, data, previousDetails) { const { details, stats } = data; const now = self.performance.now(); const elapsed = stats.loading.first ? Math.max(0, now - stats.loading.first) : 0; details.advancedDateTime = Date.now() - elapsed; const timelineOffset = this.hls.config.timelineOffset; if (timelineOffset !== details.appliedTimelineOffset) { const offset = Math.max(timelineOffset || 0, 0); details.appliedTimelineOffset = offset; details.fragments.forEach((frag) => { frag.setStart(frag.playlistOffset + offset); }); } if (details.live || previousDetails != null && previousDetails.live) { const levelOrTrack = "levelInfo" in data ? data.levelInfo : data.track; details.reloaded(previousDetails); if (previousDetails && details.fragments.length > 0) { mergeDetails(previousDetails, details, this); const error = details.playlistParsingError; if (error) { this.warn(error); const hls = this.hls; if (!hls.config.ignorePlaylistParsingErrors) { var _details$fragments$; const { networkDetails } = data; hls.trigger(Events.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.LEVEL_PARSING_ERROR, fatal: false, url: details.url, error, reason: error.message, level: data.level || void 0, parent: (_details$fragments$ = details.fragments[0]) == null ? void 0 : _details$fragments$.type, networkDetails, stats }); return; } details.playlistParsingError = null; } } if (details.requestScheduled === -1) details.requestScheduled = stats.loading.start; const bufferInfo = this.hls.mainForwardBufferInfo; const position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0; const reloadInterval = computeReloadInterval(details, (details.edge - position) * 1e3); if (details.requestScheduled + reloadInterval < now) details.requestScheduled = now; else details.requestScheduled += reloadInterval; this.log(`live playlist ${index} ${details.advanced ? "REFRESHED " + details.lastPartSn + "-" + details.lastPartIndex : details.updated ? "UPDATED" : "MISSED"}`); if (!this.canLoad || !details.live) return; let deliveryDirectives; let msn = void 0; let part = void 0; if (details.canBlockReload && details.endSN && details.advanced) { const lowLatencyMode = this.hls.config.lowLatencyMode; const lastPartSn = details.lastPartSn; const endSn = details.endSN; const lastPartIndex = details.lastPartIndex; const hasParts = lastPartIndex !== -1; const atLastPartOfSegment = lastPartSn === endSn; if (hasParts) if (atLastPartOfSegment) { msn = endSn + 1; part = lowLatencyMode ? 0 : lastPartIndex; } else { msn = lastPartSn; part = lowLatencyMode ? lastPartIndex + 1 : details.maxPartIndex; } else msn = endSn + 1; const lastAdvanced = details.age; const cdnAge = lastAdvanced + details.ageHeader; let currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5); if (currentGoal > 0) { if (cdnAge > details.targetduration * 3) { this.log(`Playlist last advanced ${lastAdvanced.toFixed(2)}s ago. Omitting segment and part directives.`); msn = void 0; part = void 0; } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) { this.warn(`CDN Tune-in goal increased from: ${previousDetails.tuneInGoal} to: ${currentGoal} with playlist age: ${details.age}`); currentGoal = 0; } else { const segments = Math.floor(currentGoal / details.targetduration); msn += segments; if (part !== void 0) { const parts = Math.round(currentGoal % details.targetduration / details.partTarget); part += parts; } this.log(`CDN Tune-in age: ${details.ageHeader}s last advanced ${lastAdvanced.toFixed(2)}s goal: ${currentGoal} skip sn ${segments} to part ${part}`); } details.tuneInGoal = currentGoal; } deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part); if (lowLatencyMode || !atLastPartOfSegment) { details.requestScheduled = now; this.loadingPlaylist(levelOrTrack, deliveryDirectives); return; } } else if (details.canBlockReload || details.canSkipUntil) deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part); if (deliveryDirectives && msn !== void 0 && details.canBlockReload) details.requestScheduled = stats.loading.first + Math.max(reloadInterval - elapsed * 2, reloadInterval / 2); this.scheduleLoading(levelOrTrack, deliveryDirectives, details); } else this.clearTimer(); } scheduleLoading(levelOrTrack, deliveryDirectives, updatedDetails) { const details = updatedDetails || levelOrTrack.details; if (!details) { this.loadingPlaylist(levelOrTrack, deliveryDirectives); return; } const now = self.performance.now(); const requestScheduled = details.requestScheduled; if (now >= requestScheduled) { this.loadingPlaylist(levelOrTrack, deliveryDirectives); return; } const estimatedTimeUntilUpdate = requestScheduled - now; this.log(`reload live playlist ${levelOrTrack.name || levelOrTrack.bitrate + "bps"} in ${Math.round(estimatedTimeUntilUpdate)} ms`); this.clearTimer(); this.timer = self.setTimeout(() => this.loadingPlaylist(levelOrTrack, deliveryDirectives), estimatedTimeUntilUpdate); } getDeliveryDirectives(details, previousDeliveryDirectives, msn, part) { let skip = getSkipValue(details); if (previousDeliveryDirectives != null && previousDeliveryDirectives.skip && details.deltaUpdateFailed) { msn = previousDeliveryDirectives.msn; part = previousDeliveryDirectives.part; skip = HlsSkip.No; } return new HlsUrlParameters(msn, part, skip); } checkRetry(errorEvent) { const errorDetails = errorEvent.details; const isTimeout = isTimeoutError(errorEvent); const errorAction = errorEvent.errorAction; const { action, retryCount = 0, retryConfig } = errorAction || {}; const retry = !!errorAction && !!retryConfig && (action === NetworkErrorAction.RetryRequest || !errorAction.resolved && action === NetworkErrorAction.SendAlternateToPenaltyBox); if (retry) { var _errorEvent$context; if (retryCount >= retryConfig.maxNumRetry) return false; if (isTimeout && (_errorEvent$context = errorEvent.context) != null && _errorEvent$context.deliveryDirectives) { this.warn(`Retrying playlist loading ${retryCount + 1}/${retryConfig.maxNumRetry} after "${errorDetails}" without delivery-directives`); this.loadPlaylist(); } else { const delay = getRetryDelay(retryConfig, retryCount); this.clearTimer(); this.timer = self.setTimeout(() => this.loadPlaylist(), delay); this.warn(`Retrying playlist loading ${retryCount + 1}/${retryConfig.maxNumRetry} after "${errorDetails}" in ${delay}ms`); } errorEvent.levelRetry = true; errorAction.resolved = true; } return retry; } }; function subtitleOptionsIdentical(trackList1, trackList2) { if (trackList1.length !== trackList2.length) return false; for (let i = 0; i < trackList1.length; i++) if (!mediaAttributesIdentical(trackList1[i].attrs, trackList2[i].attrs)) return false; return true; } function mediaAttributesIdentical(attrs1, attrs2, customAttributes) { const stableRenditionId = attrs1["STABLE-RENDITION-ID"]; if (stableRenditionId && !customAttributes) return stableRenditionId === attrs2["STABLE-RENDITION-ID"]; return !(customAttributes || [ "LANGUAGE", "NAME", "CHARACTERISTICS", "AUTOSELECT", "DEFAULT", "FORCED", "ASSOC-LANGUAGE" ]).some((subtitleAttribute) => attrs1[subtitleAttribute] !== attrs2[subtitleAttribute]); } function subtitleTrackMatchesTextTrack(subtitleTrack, textTrack) { return textTrack.label.toLowerCase() === subtitleTrack.name.toLowerCase() && (!textTrack.language || textTrack.language.toLowerCase() === (subtitleTrack.lang || "").toLowerCase()); } var AudioTrackController = class extends BasePlaylistController { constructor(hls) { super(hls, "audio-track-controller"); this.tracks = []; this.groupIds = null; this.tracksInGroup = []; this.trackId = -1; this.currentTrack = null; this.selectDefaultTrack = true; this.registerListeners(); } registerListeners() { const { hls } = this; hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this); hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const { hls } = this; hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this); hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); hls.off(Events.ERROR, this.onError, this); } destroy() { this.unregisterListeners(); this.tracks.length = 0; this.tracksInGroup.length = 0; this.currentTrack = null; super.destroy(); } onManifestLoading() { this.tracks = []; this.tracksInGroup = []; this.groupIds = null; this.currentTrack = null; this.trackId = -1; this.selectDefaultTrack = true; } onManifestParsed(event, data) { this.tracks = data.audioTracks || []; } onAudioTrackLoaded(event, data) { const { id, groupId, details } = data; const trackInActiveGroup = this.tracksInGroup[id]; if (!trackInActiveGroup || trackInActiveGroup.groupId !== groupId) { this.warn(`Audio track with id:${id} and group:${groupId} not found in active group ${trackInActiveGroup == null ? void 0 : trackInActiveGroup.groupId}`); return; } const curDetails = trackInActiveGroup.details; trackInActiveGroup.details = data.details; this.log(`Audio track ${id} "${trackInActiveGroup.name}" lang:${trackInActiveGroup.lang} group:${groupId} loaded [${details.startSN}-${details.endSN}]`); if (id === this.trackId) this.playlistLoaded(id, data, curDetails); } onLevelLoading(event, data) { this.switchLevel(data.level); } onLevelSwitching(event, data) { this.switchLevel(data.level); } switchLevel(levelIndex) { const levelInfo = this.hls.levels[levelIndex]; if (!levelInfo) return; const audioGroups = levelInfo.audioGroups || null; const currentGroups = this.groupIds; let currentTrack = this.currentTrack; if (!audioGroups || (currentGroups == null ? void 0 : currentGroups.length) !== (audioGroups == null ? void 0 : audioGroups.length) || audioGroups != null && audioGroups.some((groupId) => (currentGroups == null ? void 0 : currentGroups.indexOf(groupId)) === -1)) { this.groupIds = audioGroups; this.trackId = -1; this.currentTrack = null; const audioTracks = this.tracks.filter((track) => !audioGroups || audioGroups.indexOf(track.groupId) !== -1); if (audioTracks.length) { if (this.selectDefaultTrack && !audioTracks.some((track) => track.default)) this.selectDefaultTrack = false; audioTracks.forEach((track, i) => { track.id = i; }); } else if (!currentTrack && !this.tracksInGroup.length) return; this.tracksInGroup = audioTracks; const audioPreference = this.hls.config.audioPreference; if (!currentTrack && audioPreference) { const groupIndex = findMatchingOption(audioPreference, audioTracks, audioMatchPredicate); if (groupIndex > -1) currentTrack = audioTracks[groupIndex]; else { const allIndex = findMatchingOption(audioPreference, this.tracks); currentTrack = this.tracks[allIndex]; } } let trackId = this.findTrackId(currentTrack); if (trackId === -1 && currentTrack) trackId = this.findTrackId(null); const audioTracksUpdated = { audioTracks }; this.log(`Updating audio tracks, ${audioTracks.length} track(s) found in group(s): ${audioGroups == null ? void 0 : audioGroups.join(",")}`); this.hls.trigger(Events.AUDIO_TRACKS_UPDATED, audioTracksUpdated); const selectedTrackId = this.trackId; if (trackId !== -1 && selectedTrackId === -1) this.setAudioTrack(trackId); else if (audioTracks.length && selectedTrackId === -1) { var _this$groupIds; const error = /* @__PURE__ */ new Error(`No audio track selected for current audio group-ID(s): ${(_this$groupIds = this.groupIds) == null ? void 0 : _this$groupIds.join(",")} track count: ${audioTracks.length}`); this.warn(error.message); this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.AUDIO_TRACK_LOAD_ERROR, fatal: true, error }); } } } onError(event, data) { if (data.fatal || !data.context) return; if (data.context.type === PlaylistContextType.AUDIO_TRACK && data.context.id === this.trackId && (!this.groupIds || this.groupIds.indexOf(data.context.groupId) !== -1)) this.checkRetry(data); } get allAudioTracks() { return this.tracks; } get audioTracks() { return this.tracksInGroup; } get audioTrack() { return this.trackId; } set audioTrack(newId) { this.selectDefaultTrack = false; this.setAudioTrack(newId); } setAudioOption(audioOption) { const hls = this.hls; hls.config.audioPreference = audioOption; if (audioOption) { const allAudioTracks = this.allAudioTracks; this.selectDefaultTrack = false; if (allAudioTracks.length) { const currentTrack = this.currentTrack; if (currentTrack && matchesOption(audioOption, currentTrack, audioMatchPredicate)) return currentTrack; const groupIndex = findMatchingOption(audioOption, this.tracksInGroup, audioMatchPredicate); if (groupIndex > -1) { const track = this.tracksInGroup[groupIndex]; this.setAudioTrack(groupIndex); return track; } else if (currentTrack) { let searchIndex = hls.loadLevel; if (searchIndex === -1) searchIndex = hls.firstAutoLevel; const switchIndex = findClosestLevelWithAudioGroup(audioOption, hls.levels, allAudioTracks, searchIndex, audioMatchPredicate); if (switchIndex === -1) return null; hls.nextLoadLevel = switchIndex; } if (audioOption.channels || audioOption.audioCodec) { const withoutCodecAndChannelsMatch = findMatchingOption(audioOption, allAudioTracks); if (withoutCodecAndChannelsMatch > -1) return allAudioTracks[withoutCodecAndChannelsMatch]; } } } return null; } setAudioTrack(newId) { const tracks = this.tracksInGroup; if (newId < 0 || newId >= tracks.length) { this.warn(`Invalid audio track id: ${newId}`); return; } this.selectDefaultTrack = false; const lastTrack = this.currentTrack; const track = tracks[newId]; const trackLoaded = track.details && !track.details.live; if (newId === this.trackId && track === lastTrack && trackLoaded) return; this.log(`Switching to audio-track ${newId} "${track.name}" lang:${track.lang} group:${track.groupId} channels:${track.channels}`); this.trackId = newId; this.currentTrack = track; this.hls.trigger(Events.AUDIO_TRACK_SWITCHING, _objectSpread2({}, track)); if (trackLoaded) return; const hlsUrlParameters = this.switchParams(track.url, lastTrack == null ? void 0 : lastTrack.details, track.details); this.loadPlaylist(hlsUrlParameters); } findTrackId(currentTrack) { const audioTracks = this.tracksInGroup; for (let i = 0; i < audioTracks.length; i++) { const track = audioTracks[i]; if (this.selectDefaultTrack && !track.default) continue; if (!currentTrack || matchesOption(currentTrack, track, audioMatchPredicate)) return i; } if (currentTrack) { const { name, lang, assocLang, characteristics, audioCodec, channels } = currentTrack; for (let i = 0; i < audioTracks.length; i++) { const track = audioTracks[i]; if (matchesOption({ name, lang, assocLang, characteristics, audioCodec, channels }, track, audioMatchPredicate)) return i; } for (let i = 0; i < audioTracks.length; i++) { const track = audioTracks[i]; if (mediaAttributesIdentical(currentTrack.attrs, track.attrs, [ "LANGUAGE", "ASSOC-LANGUAGE", "CHARACTERISTICS" ])) return i; } for (let i = 0; i < audioTracks.length; i++) { const track = audioTracks[i]; if (mediaAttributesIdentical(currentTrack.attrs, track.attrs, ["LANGUAGE"])) return i; } } return -1; } loadPlaylist(hlsUrlParameters) { super.loadPlaylist(); const audioTrack = this.currentTrack; if (!this.shouldLoadPlaylist(audioTrack)) return; if (useAlternateAudio(audioTrack.url, this.hls)) this.scheduleLoading(audioTrack, hlsUrlParameters); } loadingPlaylist(audioTrack, hlsUrlParameters) { super.loadingPlaylist(audioTrack, hlsUrlParameters); const id = audioTrack.id; const groupId = audioTrack.groupId; const url = this.getUrlWithDirectives(audioTrack.url, hlsUrlParameters); const details = audioTrack.details; const age = details == null ? void 0 : details.age; this.log(`Loading audio-track ${id} "${audioTrack.name}" lang:${audioTrack.lang} group:${groupId}${(hlsUrlParameters == null ? void 0 : hlsUrlParameters.msn) !== void 0 ? " at sn " + hlsUrlParameters.msn + " part " + hlsUrlParameters.part : ""}${age && details.live ? " age " + age.toFixed(1) + (details.type ? " " + details.type || "" : "") : ""} ${url}`); this.hls.trigger(Events.AUDIO_TRACK_LOADING, { url, id, groupId, deliveryDirectives: hlsUrlParameters || null, track: audioTrack }); } }; var BufferOperationQueue = class { constructor(sourceBufferReference) { this.tracks = void 0; this.queues = { video: [], audio: [], audiovideo: [] }; this.tracks = sourceBufferReference; } destroy() { this.tracks = this.queues = null; } append(operation, type, pending) { if (this.queues === null || this.tracks === null) return; const queue = this.queues[type]; queue.push(operation); if (queue.length === 1 && !pending) this.executeNext(type); } appendBlocker(type) { return new Promise((resolve) => { const operation = { label: "async-blocker", execute: resolve, onStart: () => {}, onComplete: () => {}, onError: () => {} }; this.append(operation, type); }); } prependBlocker(type) { return new Promise((resolve) => { if (this.queues) { const operation = { label: "async-blocker-prepend", execute: resolve, onStart: () => {}, onComplete: () => {}, onError: () => {} }; this.queues[type].unshift(operation); } }); } removeBlockers() { if (this.queues === null) return; [ this.queues.video, this.queues.audio, this.queues.audiovideo ].forEach((queue) => { var _queue$; const label = (_queue$ = queue[0]) == null ? void 0 : _queue$.label; if (label === "async-blocker" || label === "async-blocker-prepend") { queue[0].execute(); queue.splice(0, 1); } }); } unblockAudio(op) { if (this.queues === null) return; if (this.queues.audio[0] === op) this.shiftAndExecuteNext("audio"); } executeNext(type) { if (this.queues === null || this.tracks === null) return; const queue = this.queues[type]; if (queue.length) { const operation = queue[0]; try { operation.execute(); } catch (error) { var _this$tracks$type; operation.onError(error); if (this.queues === null || this.tracks === null) return; const sb = (_this$tracks$type = this.tracks[type]) == null ? void 0 : _this$tracks$type.buffer; if (!(sb != null && sb.updating)) this.shiftAndExecuteNext(type); } } } shiftAndExecuteNext(type) { if (this.queues === null) return; this.queues[type].shift(); this.executeNext(type); } current(type) { var _this$queues; return ((_this$queues = this.queues) == null ? void 0 : _this$queues[type][0]) || null; } toString() { const { queues, tracks } = this; if (queues === null || tracks === null) return ``; return ` ${this.list("video")} ${this.list("audio")} ${this.list("audiovideo")}}`; } list(type) { var _this$queues2, _this$tracks; return (_this$queues2 = this.queues) != null && _this$queues2[type] || (_this$tracks = this.tracks) != null && _this$tracks[type] ? `${type}: (${this.listSbInfo(type)}) ${this.listOps(type)}` : ""; } listSbInfo(type) { var _this$tracks2; const track = (_this$tracks2 = this.tracks) == null ? void 0 : _this$tracks2[type]; const sb = track == null ? void 0 : track.buffer; if (!sb) return "none"; return `SourceBuffer${sb.updating ? " updating" : ""}${track.ended ? " ended" : ""}${track.ending ? " ending" : ""}`; } listOps(type) { var _this$queues3; return ((_this$queues3 = this.queues) == null ? void 0 : _this$queues3[type].map((op) => op.label).join(", ")) || ""; } }; var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/; var TRACK_REMOVED_ERROR_NAME = "HlsJsTrackRemovedError"; var HlsJsTrackRemovedError = class extends Error { constructor(message) { super(message); this.name = TRACK_REMOVED_ERROR_NAME; } }; var BufferController = class extends Logger { constructor(hls, fragmentTracker) { super("buffer-controller", hls.logger); this.hls = void 0; this.fragmentTracker = void 0; this.details = null; this._objectUrl = null; this.operationQueue = null; this.bufferCodecEventsTotal = 0; this.media = null; this.mediaSource = null; this.lastMpegAudioChunk = null; this.blockedAudioAppend = null; this.lastVideoAppendEnd = 0; this.appendSource = void 0; this.transferData = void 0; this.overrides = void 0; this.appendErrors = { audio: 0, video: 0, audiovideo: 0 }; this.tracks = {}; this.sourceBuffers = [[null, null], [null, null]]; this._onEndStreaming = (event) => { var _this$mediaSource; if (!this.hls) return; if (((_this$mediaSource = this.mediaSource) == null ? void 0 : _this$mediaSource.readyState) !== "open") return; this.hls.pauseBuffering(); }; this._onStartStreaming = (event) => { if (!this.hls) return; this.hls.resumeBuffering(); }; this._onMediaSourceOpen = (e) => { const { media, mediaSource } = this; if (e) this.log("Media source opened"); if (!media || !mediaSource) return; mediaSource.removeEventListener("sourceopen", this._onMediaSourceOpen); media.removeEventListener("emptied", this._onMediaEmptied); this.updateDuration(); this.hls.trigger(Events.MEDIA_ATTACHED, { media, mediaSource }); if (this.mediaSource !== null) this.checkPendingTracks(); }; this._onMediaSourceClose = () => { this.log("Media source closed"); }; this._onMediaSourceEnded = () => { this.log("Media source ended"); }; this._onMediaEmptied = () => { const { mediaSrc, _objectUrl } = this; if (mediaSrc !== _objectUrl) this.error(`Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`); }; this.hls = hls; this.fragmentTracker = fragmentTracker; this.appendSource = isManagedMediaSource(getMediaSource(hls.config.preferManagedMediaSource)); this.initTracks(); this.registerListeners(); } hasSourceTypes() { return Object.keys(this.tracks).length > 0; } destroy() { this.unregisterListeners(); this.details = null; this.lastMpegAudioChunk = this.blockedAudioAppend = null; this.transferData = this.overrides = void 0; if (this.operationQueue) { this.operationQueue.destroy(); this.operationQueue = null; } this.hls = this.fragmentTracker = null; this._onMediaSourceOpen = this._onMediaSourceClose = null; this._onMediaSourceEnded = null; this._onStartStreaming = this._onEndStreaming = null; } registerListeners() { const { hls } = this; hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.on(Events.BUFFER_RESET, this.onBufferReset, this); hls.on(Events.BUFFER_APPENDING, this.onBufferAppending, this); hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this); hls.on(Events.BUFFER_EOS, this.onBufferEos, this); hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this); hls.on(Events.FRAG_PARSED, this.onFragParsed, this); hls.on(Events.FRAG_CHANGED, this.onFragChanged, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const { hls } = this; hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.off(Events.BUFFER_RESET, this.onBufferReset, this); hls.off(Events.BUFFER_APPENDING, this.onBufferAppending, this); hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this); hls.off(Events.BUFFER_EOS, this.onBufferEos, this); hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this); hls.off(Events.FRAG_PARSED, this.onFragParsed, this); hls.off(Events.FRAG_CHANGED, this.onFragChanged, this); hls.off(Events.ERROR, this.onError, this); } transferMedia() { const { media, mediaSource } = this; if (!media) return null; const tracks = {}; if (this.operationQueue) { const updating = this.isUpdating(); if (!updating) this.operationQueue.removeBlockers(); const queued = this.isQueued(); if (updating || queued) this.warn(`Transfering MediaSource with${queued ? " operations in queue" : ""}${updating ? " updating SourceBuffer(s)" : ""} ${this.operationQueue}`); this.operationQueue.destroy(); } const transferData = this.transferData; if (!this.sourceBufferCount && transferData && transferData.mediaSource === mediaSource) _extends(tracks, transferData.tracks); else this.sourceBuffers.forEach((tuple) => { const [type] = tuple; if (type) { tracks[type] = _extends({}, this.tracks[type]); this.removeBuffer(type); } tuple[0] = tuple[1] = null; }); return { media, mediaSource, tracks }; } initTracks() { const tracks = {}; this.sourceBuffers = [[null, null], [null, null]]; this.tracks = tracks; this.resetQueue(); this.resetAppendErrors(); this.lastMpegAudioChunk = this.blockedAudioAppend = null; this.lastVideoAppendEnd = 0; } onManifestLoading() { this.bufferCodecEventsTotal = 0; this.details = null; } onManifestParsed(event, data) { var _this$transferData; let codecEvents = 2; if (data.audio && !data.video || !data.altAudio) codecEvents = 1; this.bufferCodecEventsTotal = codecEvents; this.log(`${codecEvents} bufferCodec event(s) expected.`); if ((_this$transferData = this.transferData) != null && _this$transferData.mediaSource && this.sourceBufferCount && codecEvents) this.bufferCreated(); } onMediaAttaching(event, data) { const media = this.media = data.media; this.transferData = this.overrides = void 0; const MediaSource = getMediaSource(this.appendSource); if (MediaSource) { const transferringMedia = !!data.mediaSource; if (transferringMedia || data.overrides) { this.transferData = data; this.overrides = data.overrides; } const ms = this.mediaSource = data.mediaSource || new MediaSource(); this.assignMediaSource(ms); if (transferringMedia) { this._objectUrl = media.src; this.attachTransferred(); } else { const objectUrl = this._objectUrl = self.URL.createObjectURL(ms); if (this.appendSource) try { media.removeAttribute("src"); const MMS = self.ManagedMediaSource; media.disableRemotePlayback = media.disableRemotePlayback || MMS && ms instanceof MMS; removeSourceChildren(media); addSource(media, objectUrl); media.load(); } catch (error) { media.src = objectUrl; } else media.src = objectUrl; } media.addEventListener("emptied", this._onMediaEmptied); } } assignMediaSource(ms) { var _this$transferData2, _ms$constructor; this.log(`${((_this$transferData2 = this.transferData) == null ? void 0 : _this$transferData2.mediaSource) === ms ? "transferred" : "created"} media source: ${(_ms$constructor = ms.constructor) == null ? void 0 : _ms$constructor.name}`); ms.addEventListener("sourceopen", this._onMediaSourceOpen); ms.addEventListener("sourceended", this._onMediaSourceEnded); ms.addEventListener("sourceclose", this._onMediaSourceClose); if (this.appendSource) { ms.addEventListener("startstreaming", this._onStartStreaming); ms.addEventListener("endstreaming", this._onEndStreaming); } } attachTransferred() { const media = this.media; const data = this.transferData; if (!data || !media) return; const requiredTracks = this.tracks; const transferredTracks = data.tracks; const trackNames = transferredTracks ? Object.keys(transferredTracks) : null; const trackCount = trackNames ? trackNames.length : 0; const mediaSourceOpenCallback = () => { Promise.resolve().then(() => { if (this.media && this.mediaSourceOpenOrEnded) this._onMediaSourceOpen(); }); }; if (transferredTracks && trackNames && trackCount) { if (!this.tracksReady) { this.hls.config.startFragPrefetch = true; this.log(`attachTransferred: waiting for SourceBuffer track info`); return; } this.log(`attachTransferred: (bufferCodecEventsTotal ${this.bufferCodecEventsTotal}) required tracks: ${stringify(requiredTracks, (key, value) => key === "initSegment" ? void 0 : value)}; transfer tracks: ${stringify(transferredTracks, (key, value) => key === "initSegment" ? void 0 : value)}}`); if (!isCompatibleTrackChange(transferredTracks, requiredTracks)) { data.mediaSource = null; data.tracks = void 0; const currentTime = media.currentTime; const details = this.details; const startTime = Math.max(currentTime, (details == null ? void 0 : details.fragments[0].start) || 0); if (startTime - currentTime > 1) { this.log(`attachTransferred: waiting for playback to reach new tracks start time ${currentTime} -> ${startTime}`); return; } this.warn(`attachTransferred: resetting MediaSource for incompatible tracks ("${Object.keys(transferredTracks)}"->"${Object.keys(requiredTracks)}") start time: ${startTime} currentTime: ${currentTime}`); this.onMediaDetaching(Events.MEDIA_DETACHING, {}); this.onMediaAttaching(Events.MEDIA_ATTACHING, data); media.currentTime = startTime; return; } this.transferData = void 0; trackNames.forEach((trackName) => { const type = trackName; const track = transferredTracks[type]; if (track) { const sb = track.buffer; if (sb) { const fragmentTracker = this.fragmentTracker; const playlistType = track.id; if (fragmentTracker.hasFragments(playlistType) || fragmentTracker.hasParts(playlistType)) { const bufferedTimeRanges = BufferHelper.getBuffered(sb); fragmentTracker.detectEvictedFragments(type, bufferedTimeRanges, playlistType, null, true); } const sbIndex = sourceBufferNameToIndex(type); const sbTuple = [type, sb]; this.sourceBuffers[sbIndex] = sbTuple; if (sb.updating && this.operationQueue) this.operationQueue.prependBlocker(type); this.trackSourceBuffer(type, track); } } }); mediaSourceOpenCallback(); this.bufferCreated(); } else { this.log(`attachTransferred: MediaSource w/o SourceBuffers`); mediaSourceOpenCallback(); } } get mediaSourceOpenOrEnded() { var _this$mediaSource2; const readyState = (_this$mediaSource2 = this.mediaSource) == null ? void 0 : _this$mediaSource2.readyState; return readyState === "open" || readyState === "ended"; } onMediaDetaching(event, data) { const transferringMedia = !!data.transferMedia; this.transferData = this.overrides = void 0; const { media, mediaSource, _objectUrl } = this; if (mediaSource) { this.log(`media source ${transferringMedia ? "transferring" : "detaching"}`); if (transferringMedia) { this.sourceBuffers.forEach(([type]) => { if (type) this.removeBuffer(type); }); this.resetQueue(); } else { if (this.mediaSourceOpenOrEnded) { const open = mediaSource.readyState === "open"; try { const sourceBuffers = mediaSource.sourceBuffers; for (let i = sourceBuffers.length; i--;) { if (open) sourceBuffers[i].abort(); mediaSource.removeSourceBuffer(sourceBuffers[i]); } if (open) mediaSource.endOfStream(); } catch (err) { this.warn(`onMediaDetaching: ${err.message} while calling endOfStream`); } } if (this.sourceBufferCount) this.onBufferReset(); } mediaSource.removeEventListener("sourceopen", this._onMediaSourceOpen); mediaSource.removeEventListener("sourceended", this._onMediaSourceEnded); mediaSource.removeEventListener("sourceclose", this._onMediaSourceClose); if (this.appendSource) { mediaSource.removeEventListener("startstreaming", this._onStartStreaming); mediaSource.removeEventListener("endstreaming", this._onEndStreaming); } this.mediaSource = null; this._objectUrl = null; } if (media) { media.removeEventListener("emptied", this._onMediaEmptied); if (!transferringMedia) { if (_objectUrl) self.URL.revokeObjectURL(_objectUrl); if (this.mediaSrc === _objectUrl) { media.removeAttribute("src"); if (this.appendSource) removeSourceChildren(media); media.load(); } else this.warn("media|source.src was changed by a third party - skip cleanup"); } this.media = null; } this.hls.trigger(Events.MEDIA_DETACHED, data); } onBufferReset() { this.sourceBuffers.forEach(([type]) => { if (type) this.resetBuffer(type); }); this.initTracks(); } resetBuffer(type) { var _this$tracks$type; const sb = (_this$tracks$type = this.tracks[type]) == null ? void 0 : _this$tracks$type.buffer; this.removeBuffer(type); if (sb) try { var _this$mediaSource3; if ((_this$mediaSource3 = this.mediaSource) != null && _this$mediaSource3.sourceBuffers.length) this.mediaSource.removeSourceBuffer(sb); } catch (err) { this.warn(`onBufferReset ${type}`, err); } delete this.tracks[type]; } removeBuffer(type) { this.removeBufferListeners(type); this.sourceBuffers[sourceBufferNameToIndex(type)] = [null, null]; const track = this.tracks[type]; if (track) track.buffer = void 0; } resetQueue() { if (this.operationQueue) this.operationQueue.destroy(); this.operationQueue = new BufferOperationQueue(this.tracks); } onBufferCodecs(event, data) { var _data$audio; const tracks = this.tracks; const trackNames = Object.keys(data); this.log(`BUFFER_CODECS: "${trackNames}" (current SB count ${this.sourceBufferCount})`); const unmuxedToMuxed = "audiovideo" in data && (tracks.audio || tracks.video) || tracks.audiovideo && ("audio" in data || "video" in data); const muxedToUnmuxed = !unmuxedToMuxed && this.sourceBufferCount && this.media && trackNames.some((sbName) => !tracks[sbName]); if (unmuxedToMuxed || muxedToUnmuxed) { this.warn(`Unsupported transition between "${Object.keys(tracks)}" and "${trackNames}" SourceBuffers`); return; } trackNames.forEach((trackName) => { var _this$transferData3, _trackCodec; const { id, codec, levelCodec, container, metadata, supplemental } = data[trackName]; let track = tracks[trackName]; const transferredTrack = (_this$transferData3 = this.transferData) == null || (_this$transferData3 = _this$transferData3.tracks) == null ? void 0 : _this$transferData3[trackName]; const sbTrack = transferredTrack != null && transferredTrack.buffer ? transferredTrack : track; const sbCodec = (sbTrack == null ? void 0 : sbTrack.pendingCodec) || (sbTrack == null ? void 0 : sbTrack.codec); const trackLevelCodec = sbTrack == null ? void 0 : sbTrack.levelCodec; if (!track) track = tracks[trackName] = { buffer: void 0, listeners: [], codec, supplemental, container, levelCodec, metadata, id }; const currentCodecFull = pickMostCompleteCodecName(sbCodec, trackLevelCodec); const currentCodec = currentCodecFull == null ? void 0 : currentCodecFull.replace(VIDEO_CODEC_PROFILE_REPLACE, "$1"); let trackCodec = pickMostCompleteCodecName(codec, levelCodec); const nextCodec = (_trackCodec = trackCodec) == null ? void 0 : _trackCodec.replace(VIDEO_CODEC_PROFILE_REPLACE, "$1"); if (trackCodec && currentCodecFull && currentCodec !== nextCodec) { if (trackName.slice(0, 5) === "audio") trackCodec = getCodecCompatibleName(trackCodec, this.appendSource); this.log(`switching codec ${sbCodec} to ${trackCodec}`); if (trackCodec !== (track.pendingCodec || track.codec)) track.pendingCodec = trackCodec; track.container = container; this.appendChangeType(trackName, container, trackCodec); } }); if (this.tracksReady || this.sourceBufferCount) data.tracks = this.sourceBufferTracks; if (this.sourceBufferCount) return; if (this.bufferCodecEventsTotal > 1 && !this.tracks.video && !data.video && ((_data$audio = data.audio) == null ? void 0 : _data$audio.id) === "main") { this.log(`Main audio-only`); this.bufferCodecEventsTotal = 1; } if (this.mediaSourceOpenOrEnded) this.checkPendingTracks(); } get sourceBufferTracks() { return Object.keys(this.tracks).reduce((baseTracks, type) => { const track = this.tracks[type]; baseTracks[type] = { id: track.id, container: track.container, codec: track.codec, levelCodec: track.levelCodec }; return baseTracks; }, {}); } appendChangeType(type, container, codec) { const mimeType = `${container};codecs=${codec}`; const operation = { label: `change-type=${mimeType}`, execute: () => { const track = this.tracks[type]; if (track) { const sb = track.buffer; if (sb != null && sb.changeType) { this.log(`changing ${type} sourceBuffer type to ${mimeType}`); sb.changeType(mimeType); track.codec = codec; track.container = container; } } this.shiftAndExecuteNext(type); }, onStart: () => {}, onComplete: () => {}, onError: (error) => { this.warn(`Failed to change ${type} SourceBuffer type`, error); } }; this.append(operation, type, this.isPending(this.tracks[type])); } blockAudio(partOrFrag) { var _this$fragmentTracker; const pStart = partOrFrag.start; const pTime = pStart + partOrFrag.duration * .05; if (((_this$fragmentTracker = this.fragmentTracker.getAppendedFrag(pStart, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker.gap) === true) return; const op = { label: "block-audio", execute: () => { var _this$fragmentTracker2; const videoTrack = this.tracks.video; if (this.lastVideoAppendEnd > pTime || videoTrack != null && videoTrack.buffer && BufferHelper.isBuffered(videoTrack.buffer, pTime) || ((_this$fragmentTracker2 = this.fragmentTracker.getAppendedFrag(pTime, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker2.gap) === true) { this.blockedAudioAppend = null; this.shiftAndExecuteNext("audio"); } }, onStart: () => {}, onComplete: () => {}, onError: (error) => { this.warn("Error executing block-audio operation", error); } }; this.blockedAudioAppend = { op, frag: partOrFrag }; this.append(op, "audio", true); } unblockAudio() { const { blockedAudioAppend, operationQueue } = this; if (blockedAudioAppend && operationQueue) { this.blockedAudioAppend = null; operationQueue.unblockAudio(blockedAudioAppend.op); } } onBufferAppending(event, eventData) { const { tracks } = this; const { data, type, parent, frag, part, chunkMeta, offset } = eventData; const chunkStats = chunkMeta.buffering[type]; const { sn, cc } = frag; const bufferAppendingStart = self.performance.now(); chunkStats.start = bufferAppendingStart; const fragBuffering = frag.stats.buffering; const partBuffering = part ? part.stats.buffering : null; if (fragBuffering.start === 0) fragBuffering.start = bufferAppendingStart; if (partBuffering && partBuffering.start === 0) partBuffering.start = bufferAppendingStart; const audioTrack = tracks.audio; let checkTimestampOffset = false; if (type === "audio" && (audioTrack == null ? void 0 : audioTrack.container) === "audio/mpeg") { checkTimestampOffset = !this.lastMpegAudioChunk || chunkMeta.id === 1 || this.lastMpegAudioChunk.sn !== chunkMeta.sn; this.lastMpegAudioChunk = chunkMeta; } const videoTrack = tracks.video; const videoSb = videoTrack == null ? void 0 : videoTrack.buffer; if (videoSb && sn !== "initSegment") { const partOrFrag = part || frag; const blockedAudioAppend = this.blockedAudioAppend; if (type === "audio" && parent !== "main" && !this.blockedAudioAppend && !(videoTrack.ending || videoTrack.ended)) { const pTime = partOrFrag.start + partOrFrag.duration * .05; const vbuffered = videoSb.buffered; const vappending = this.currentOp("video"); if (!vbuffered.length && !vappending) this.blockAudio(partOrFrag); else if (!vappending && !BufferHelper.isBuffered(videoSb, pTime) && this.lastVideoAppendEnd < pTime) this.blockAudio(partOrFrag); } else if (type === "video") { const videoAppendEnd = partOrFrag.end; if (blockedAudioAppend) { const audioStart = blockedAudioAppend.frag.start; if (videoAppendEnd > audioStart || videoAppendEnd < this.lastVideoAppendEnd || BufferHelper.isBuffered(videoSb, audioStart)) this.unblockAudio(); } this.lastVideoAppendEnd = videoAppendEnd; } } const fragStart = (part || frag).start; const operation = { label: `append-${type}`, execute: () => { var _this$tracks$type2; chunkStats.executeStart = self.performance.now(); const sb = (_this$tracks$type2 = this.tracks[type]) == null ? void 0 : _this$tracks$type2.buffer; if (sb) { if (checkTimestampOffset) this.updateTimestampOffset(sb, fragStart, .1, type, sn, cc); else if (offset !== void 0 && isFiniteNumber(offset)) this.updateTimestampOffset(sb, offset, 1e-6, type, sn, cc); } this.appendExecutor(data, type); }, onStart: () => {}, onComplete: () => { const end = self.performance.now(); chunkStats.executeEnd = chunkStats.end = end; if (fragBuffering.first === 0) fragBuffering.first = end; if (partBuffering && partBuffering.first === 0) partBuffering.first = end; const timeRanges = {}; this.sourceBuffers.forEach(([type, sb]) => { if (type) timeRanges[type] = BufferHelper.getBuffered(sb); }); this.appendErrors[type] = 0; if (type === "audio" || type === "video") this.appendErrors.audiovideo = 0; else { this.appendErrors.audio = 0; this.appendErrors.video = 0; } this.hls.trigger(Events.BUFFER_APPENDED, { type, frag, part, chunkMeta, parent: frag.type, timeRanges }); }, onError: (error) => { var _this$media; const event = { type: ErrorTypes.MEDIA_ERROR, parent: frag.type, details: ErrorDetails.BUFFER_APPEND_ERROR, sourceBufferName: type, frag, part, chunkMeta, error, err: error, fatal: false }; const mediaError = (_this$media = this.media) == null ? void 0 : _this$media.error; if (error.code === DOMException.QUOTA_EXCEEDED_ERR || error.name == "QuotaExceededError" || `quota` in error) event.details = ErrorDetails.BUFFER_FULL_ERROR; else if (error.code === DOMException.INVALID_STATE_ERR && this.mediaSourceOpenOrEnded && !mediaError) event.errorAction = createDoNothingErrorAction(true); else if (error.name === TRACK_REMOVED_ERROR_NAME && this.sourceBufferCount === 0) event.errorAction = createDoNothingErrorAction(true); else { const appendErrorCount = ++this.appendErrors[type]; this.warn(`Failed ${appendErrorCount}/${this.hls.config.appendErrorMaxRetry} times to append segment in "${type}" sourceBuffer (${mediaError ? mediaError : "no media error"})`); if (appendErrorCount >= this.hls.config.appendErrorMaxRetry || !!mediaError) event.fatal = true; } this.hls.trigger(Events.ERROR, event); } }; this.log(`queuing "${type}" append sn: ${sn}${part ? " p: " + part.index : ""} of ${frag.type === PlaylistLevelType.MAIN ? "level" : "track"} ${frag.level} cc: ${cc}`); this.append(operation, type, this.isPending(this.tracks[type])); } getFlushOp(type, start, end) { this.log(`queuing "${type}" remove ${start}-${end}`); return { label: "remove", execute: () => { this.removeExecutor(type, start, end); }, onStart: () => {}, onComplete: () => { this.hls.trigger(Events.BUFFER_FLUSHED, { type }); }, onError: (error) => { this.warn(`Failed to remove ${start}-${end} from "${type}" SourceBuffer`, error); } }; } onBufferFlushing(event, data) { const { type, startOffset, endOffset } = data; if (type) this.append(this.getFlushOp(type, startOffset, endOffset), type); else this.sourceBuffers.forEach(([type]) => { if (type) this.append(this.getFlushOp(type, startOffset, endOffset), type); }); } onFragParsed(event, data) { const { frag, part } = data; const buffersAppendedTo = []; const elementaryStreams = part ? part.elementaryStreams : frag.elementaryStreams; if (elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO]) buffersAppendedTo.push("audiovideo"); else { if (elementaryStreams[ElementaryStreamTypes.AUDIO]) buffersAppendedTo.push("audio"); if (elementaryStreams[ElementaryStreamTypes.VIDEO]) buffersAppendedTo.push("video"); } const onUnblocked = () => { const now = self.performance.now(); frag.stats.buffering.end = now; if (part) part.stats.buffering.end = now; const stats = part ? part.stats : frag.stats; this.hls.trigger(Events.FRAG_BUFFERED, { frag, part, stats, id: frag.type }); }; if (buffersAppendedTo.length === 0) this.warn(`Fragments must have at least one ElementaryStreamType set. type: ${frag.type} level: ${frag.level} sn: ${frag.sn}`); this.blockBuffers(onUnblocked, buffersAppendedTo).catch((error) => { this.warn(`Fragment buffered callback ${error}`); this.stepOperationQueue(this.sourceBufferTypes); }); } onFragChanged(event, data) { this.trimBuffers(); } get bufferedToEnd() { return this.sourceBufferCount > 0 && !this.sourceBuffers.some(([type]) => { if (type) { const track = this.tracks[type]; if (track) return !track.ended || track.ending; } return false; }); } onBufferEos(event, data) { var _this$overrides; this.sourceBuffers.forEach(([type]) => { if (type) { const track = this.tracks[type]; if (!data.type || data.type === type) { track.ending = true; if (!track.ended) { track.ended = true; this.log(`${type} buffer reached EOS`); } } } }); const allowEndOfStream = ((_this$overrides = this.overrides) == null ? void 0 : _this$overrides.endOfStream) !== false; if (this.sourceBufferCount > 0 && !this.sourceBuffers.some(([type]) => { var _this$tracks$type3; return type && !((_this$tracks$type3 = this.tracks[type]) != null && _this$tracks$type3.ended); })) if (allowEndOfStream) { this.log(`Queueing EOS`); this.blockUntilOpen(() => { this.tracksEnded(); const { mediaSource } = this; if (!mediaSource || mediaSource.readyState !== "open") { if (mediaSource) this.log(`Could not call mediaSource.endOfStream(). mediaSource.readyState: ${mediaSource.readyState}`); return; } this.log(`Calling mediaSource.endOfStream()`); mediaSource.endOfStream(); this.hls.trigger(Events.BUFFERED_TO_END, void 0); }); } else { this.tracksEnded(); this.hls.trigger(Events.BUFFERED_TO_END, void 0); } else if (data.type === "video") this.unblockAudio(); } tracksEnded() { this.sourceBuffers.forEach(([type]) => { if (type !== null) { const track = this.tracks[type]; if (track) track.ending = false; } }); } onLevelUpdated(event, { details }) { if (!details.fragments.length) return; this.details = details; this.updateDuration(); } updateDuration() { this.blockUntilOpen(() => { const durationAndRange = this.getDurationAndRange(); if (!durationAndRange) return; this.updateMediaSource(durationAndRange); }); } onError(event, data) { if (data.details === ErrorDetails.BUFFER_APPEND_ERROR && data.frag) { var _data$errorAction; const nextAutoLevel = (_data$errorAction = data.errorAction) == null ? void 0 : _data$errorAction.nextAutoLevel; if (isFiniteNumber(nextAutoLevel) && nextAutoLevel !== data.frag.level) this.resetAppendErrors(); } } resetAppendErrors() { this.appendErrors = { audio: 0, video: 0, audiovideo: 0 }; } trimBuffers() { const { hls, details, media } = this; if (!media || details === null) return; if (!this.sourceBufferCount) return; const config = hls.config; const currentTime = media.currentTime; const targetDuration = details.levelTargetDuration; const backBufferLength = details.live && config.liveBackBufferLength !== null ? config.liveBackBufferLength : config.backBufferLength; if (isFiniteNumber(backBufferLength) && backBufferLength >= 0) { const maxBackBufferLength = Math.max(backBufferLength, targetDuration); const targetBackBufferPosition = Math.floor(currentTime / targetDuration) * targetDuration - maxBackBufferLength; this.flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition); } const frontBufferFlushThreshold = config.frontBufferFlushThreshold; if (isFiniteNumber(frontBufferFlushThreshold) && frontBufferFlushThreshold > 0) { const frontBufferLength = Math.max(config.maxBufferLength, frontBufferFlushThreshold); const maxFrontBufferLength = Math.max(frontBufferLength, targetDuration); const targetFrontBufferPosition = Math.floor(currentTime / targetDuration) * targetDuration + maxFrontBufferLength; this.flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition); } } flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition) { this.sourceBuffers.forEach(([type, sb]) => { if (sb) { const buffered = BufferHelper.getBuffered(sb); if (buffered.length > 0 && targetBackBufferPosition > buffered.start(0)) { var _this$details; this.hls.trigger(Events.BACK_BUFFER_REACHED, { bufferEnd: targetBackBufferPosition }); const track = this.tracks[type]; if ((_this$details = this.details) != null && _this$details.live) this.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, { bufferEnd: targetBackBufferPosition }); else if (track != null && track.ended) { this.log(`Cannot flush ${type} back buffer while SourceBuffer is in ended state`); return; } this.hls.trigger(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: targetBackBufferPosition, type }); } } }); } flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition) { this.sourceBuffers.forEach(([type, sb]) => { if (sb) { const buffered = BufferHelper.getBuffered(sb); const numBufferedRanges = buffered.length; if (numBufferedRanges < 2) return; const bufferStart = buffered.start(numBufferedRanges - 1); const bufferEnd = buffered.end(numBufferedRanges - 1); if (targetFrontBufferPosition > bufferStart || currentTime >= bufferStart && currentTime <= bufferEnd) return; this.hls.trigger(Events.BUFFER_FLUSHING, { startOffset: bufferStart, endOffset: Infinity, type }); } }); } /** * Update Media Source duration to current level duration or override to Infinity if configuration parameter * 'liveDurationInfinity` is set to `true` * More details: https://github.com/video-dev/hls.js/issues/355 */ getDurationAndRange() { var _this$overrides2; const { details, mediaSource } = this; if (!details || !this.media || (mediaSource == null ? void 0 : mediaSource.readyState) !== "open") return null; const playlistEnd = details.edge; if (details.live && this.hls.config.liveDurationInfinity) { if (details.fragments.length && !!mediaSource.setLiveSeekableRange) { const start = Math.max(0, details.fragmentStart); return { duration: Infinity, start, end: Math.max(start, playlistEnd) }; } return { duration: Infinity }; } const overrideDuration = (_this$overrides2 = this.overrides) == null ? void 0 : _this$overrides2.duration; if (overrideDuration) { if (!isFiniteNumber(overrideDuration)) return null; return { duration: overrideDuration }; } const mediaDuration = this.media.duration; if (playlistEnd > (isFiniteNumber(mediaSource.duration) ? mediaSource.duration : 0) && playlistEnd > mediaDuration || !isFiniteNumber(mediaDuration)) return { duration: playlistEnd }; return null; } updateMediaSource({ duration, start, end }) { const mediaSource = this.mediaSource; if (!this.media || !mediaSource || mediaSource.readyState !== "open") return; if (mediaSource.duration !== duration) { if (isFiniteNumber(duration)) this.log(`Updating MediaSource duration to ${duration.toFixed(3)}`); mediaSource.duration = duration; } if (start !== void 0 && end !== void 0) { this.log(`MediaSource duration is set to ${mediaSource.duration}. Setting seekable range to ${start}-${end}.`); mediaSource.setLiveSeekableRange(start, end); } } get tracksReady() { const pendingTrackCount = this.pendingTrackCount; return pendingTrackCount > 0 && (pendingTrackCount >= this.bufferCodecEventsTotal || this.isPending(this.tracks.audiovideo)); } checkPendingTracks() { const { bufferCodecEventsTotal, pendingTrackCount, tracks } = this; this.log(`checkPendingTracks (pending: ${pendingTrackCount} codec events expected: ${bufferCodecEventsTotal}) ${stringify(tracks)}`); if (this.tracksReady) { var _this$transferData4; const transferredTracks = (_this$transferData4 = this.transferData) == null ? void 0 : _this$transferData4.tracks; if (transferredTracks && Object.keys(transferredTracks).length) this.attachTransferred(); else this.createSourceBuffers(); } } bufferCreated() { if (this.sourceBufferCount) { const tracks = {}; this.sourceBuffers.forEach(([type, buffer]) => { if (type) { const track = this.tracks[type]; tracks[type] = { buffer, container: track.container, codec: track.codec, supplemental: track.supplemental, levelCodec: track.levelCodec, id: track.id, metadata: track.metadata }; } }); this.hls.trigger(Events.BUFFER_CREATED, { tracks }); this.log(`SourceBuffers created. Running queue: ${this.operationQueue}`); this.sourceBuffers.forEach(([type]) => { this.executeNext(type); }); } else { const error = /* @__PURE__ */ new Error("could not create source buffer for media codec(s)"); this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_INCOMPATIBLE_CODECS_ERROR, fatal: true, error, reason: error.message }); } } createSourceBuffers() { const { tracks, sourceBuffers, mediaSource } = this; if (!mediaSource) throw new Error("createSourceBuffers called when mediaSource was null"); for (const trackName in tracks) { const type = trackName; const track = tracks[type]; if (this.isPending(track)) { const codec = this.getTrackCodec(track, type); const mimeType = `${track.container};codecs=${codec}`; track.codec = codec; this.log(`creating sourceBuffer(${mimeType})${this.currentOp(type) ? " Queued" : ""} ${stringify(track)}`); try { const sb = mediaSource.addSourceBuffer(mimeType); const sbIndex = sourceBufferNameToIndex(type); sourceBuffers[sbIndex] = [type, sb]; track.buffer = sb; } catch (error) { var _this$operationQueue; this.error(`error while trying to add sourceBuffer: ${error.message}`); this.shiftAndExecuteNext(type); (_this$operationQueue = this.operationQueue) == null || _this$operationQueue.removeBlockers(); delete this.tracks[type]; this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_ADD_CODEC_ERROR, fatal: false, error, sourceBufferName: type, mimeType, parent: track.id }); return; } this.trackSourceBuffer(type, track); } } this.bufferCreated(); } getTrackCodec(track, trackName) { const supplementalCodec = track.supplemental; let trackCodec = track.codec; if (supplementalCodec && (trackName === "video" || trackName === "audiovideo") && areCodecsMediaSourceSupported(supplementalCodec, "video")) trackCodec = replaceVideoCodec(trackCodec, supplementalCodec); const codec = pickMostCompleteCodecName(trackCodec, track.levelCodec); if (codec) { if (trackName.slice(0, 5) === "audio") return getCodecCompatibleName(codec, this.appendSource); return codec; } return ""; } trackSourceBuffer(type, track) { const buffer = track.buffer; if (!buffer) return; const codec = this.getTrackCodec(track, type); this.tracks[type] = { buffer, codec, container: track.container, levelCodec: track.levelCodec, supplemental: track.supplemental, metadata: track.metadata, id: track.id, listeners: [] }; this.removeBufferListeners(type); this.addBufferListener(type, "updatestart", this.onSBUpdateStart); this.addBufferListener(type, "updateend", this.onSBUpdateEnd); this.addBufferListener(type, "error", this.onSBUpdateError); if (this.appendSource) this.addBufferListener(type, "bufferedchange", (type, event) => { const removedRanges = event.removedRanges; if (removedRanges != null && removedRanges.length) this.hls.trigger(Events.BUFFER_FLUSHED, { type }); }); } get mediaSrc() { var _this$media2, _this$media2$querySel; const media = ((_this$media2 = this.media) == null || (_this$media2$querySel = _this$media2.querySelector) == null ? void 0 : _this$media2$querySel.call(_this$media2, "source")) || this.media; return media == null ? void 0 : media.src; } onSBUpdateStart(type) { const operation = this.currentOp(type); if (!operation) return; operation.onStart(); } onSBUpdateEnd(type) { var _this$mediaSource4; if (((_this$mediaSource4 = this.mediaSource) == null ? void 0 : _this$mediaSource4.readyState) === "closed") { this.resetBuffer(type); return; } const operation = this.currentOp(type); if (!operation) return; operation.onComplete(); this.shiftAndExecuteNext(type); } onSBUpdateError(type, event) { var _this$mediaSource5; const error = /* @__PURE__ */ new Error(`${type} SourceBuffer error. MediaSource readyState: ${(_this$mediaSource5 = this.mediaSource) == null ? void 0 : _this$mediaSource5.readyState}`); this.error(`${error}`, event); this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_APPENDING_ERROR, sourceBufferName: type, error, fatal: false }); const operation = this.currentOp(type); if (operation) operation.onError(error); } updateTimestampOffset(sb, timestampOffset, tolerance, type, sn, cc) { const delta = timestampOffset - sb.timestampOffset; if (Math.abs(delta) >= tolerance) { this.log(`Updating ${type} SourceBuffer timestampOffset to ${timestampOffset} (sn: ${sn} cc: ${cc})`); sb.timestampOffset = timestampOffset; } } removeExecutor(type, startOffset, endOffset) { const { media, mediaSource } = this; const track = this.tracks[type]; const sb = track == null ? void 0 : track.buffer; if (!media || !mediaSource || !sb) { this.warn(`Attempting to remove from the ${type} SourceBuffer, but it does not exist`); this.shiftAndExecuteNext(type); return; } const mediaDuration = isFiniteNumber(media.duration) ? media.duration : Infinity; const msDuration = isFiniteNumber(mediaSource.duration) ? mediaSource.duration : Infinity; const removeStart = Math.max(0, startOffset); const removeEnd = Math.min(endOffset, mediaDuration, msDuration); if (removeEnd > removeStart && (!track.ending || track.ended)) { track.ended = false; this.log(`Removing [${removeStart},${removeEnd}] from the ${type} SourceBuffer`); sb.remove(removeStart, removeEnd); } else this.shiftAndExecuteNext(type); } appendExecutor(data, type) { const track = this.tracks[type]; const sb = track == null ? void 0 : track.buffer; if (!sb) throw new HlsJsTrackRemovedError(`Attempting to append to the ${type} SourceBuffer, but it does not exist`); track.ending = false; track.ended = false; sb.appendBuffer(data); } blockUntilOpen(callback) { if (this.isUpdating() || this.isQueued()) this.blockBuffers(callback).catch((error) => { this.warn(`SourceBuffer blocked callback ${error}`); this.stepOperationQueue(this.sourceBufferTypes); }); else try { callback(); } catch (error) { this.warn(`Callback run without blocking ${this.operationQueue} ${error}`); } } isUpdating() { return this.sourceBuffers.some(([type, sb]) => type && sb.updating); } isQueued() { return this.sourceBuffers.some(([type]) => type && !!this.currentOp(type)); } isPending(track) { return !!track && !track.buffer; } blockBuffers(onUnblocked, bufferNames = this.sourceBufferTypes) { if (!bufferNames.length) { this.log("Blocking operation requested, but no SourceBuffers exist"); return Promise.resolve().then(onUnblocked); } const { operationQueue } = this; const blockingOperations = bufferNames.map((type) => this.appendBlocker(type)); if (bufferNames.length > 1 && !!this.blockedAudioAppend) this.unblockAudio(); return Promise.all(blockingOperations).then((result) => { if (operationQueue !== this.operationQueue) return; onUnblocked(); this.stepOperationQueue(this.sourceBufferTypes); }); } stepOperationQueue(bufferNames) { bufferNames.forEach((type) => { var _this$tracks$type4; const sb = (_this$tracks$type4 = this.tracks[type]) == null ? void 0 : _this$tracks$type4.buffer; if (!sb || sb.updating) return; this.shiftAndExecuteNext(type); }); } append(operation, type, pending) { if (this.operationQueue) this.operationQueue.append(operation, type, pending); } appendBlocker(type) { if (this.operationQueue) return this.operationQueue.appendBlocker(type); } currentOp(type) { if (this.operationQueue) return this.operationQueue.current(type); return null; } executeNext(type) { if (type && this.operationQueue) this.operationQueue.executeNext(type); } shiftAndExecuteNext(type) { if (this.operationQueue) this.operationQueue.shiftAndExecuteNext(type); } get pendingTrackCount() { return Object.keys(this.tracks).reduce((acc, type) => acc + (this.isPending(this.tracks[type]) ? 1 : 0), 0); } get sourceBufferCount() { return this.sourceBuffers.reduce((acc, [type]) => acc + (type ? 1 : 0), 0); } get sourceBufferTypes() { return this.sourceBuffers.map(([type]) => type).filter((type) => !!type); } addBufferListener(type, event, fn) { const track = this.tracks[type]; if (!track) return; const buffer = track.buffer; if (!buffer) return; const listener = fn.bind(this, type); track.listeners.push({ event, listener }); buffer.addEventListener(event, listener); } removeBufferListeners(type) { const track = this.tracks[type]; if (!track) return; const buffer = track.buffer; if (!buffer) return; track.listeners.forEach((l) => { buffer.removeEventListener(l.event, l.listener); }); track.listeners.length = 0; } }; function removeSourceChildren(node) { const sourceChildren = node.querySelectorAll("source"); [].slice.call(sourceChildren).forEach((source) => { node.removeChild(source); }); } function addSource(media, url) { const source = self.document.createElement("source"); source.type = "video/mp4"; source.src = url; media.appendChild(source); } function sourceBufferNameToIndex(type) { return type === "audio" ? 1 : 0; } var CapLevelController = class CapLevelController { constructor(hls) { this.hls = void 0; this.autoLevelCapping = void 0; this.firstLevel = void 0; this.media = void 0; this.restrictedLevels = void 0; this.timer = void 0; this.clientRect = void 0; this.streamController = void 0; this.hls = hls; this.autoLevelCapping = Number.POSITIVE_INFINITY; this.firstLevel = -1; this.media = null; this.restrictedLevels = []; this.timer = void 0; this.clientRect = null; this.registerListeners(); } setStreamController(streamController) { this.streamController = streamController; } destroy() { if (this.hls) this.unregisterListener(); if (this.timer) this.stopCapping(); this.media = null; this.clientRect = null; this.hls = this.streamController = null; } registerListeners() { const { hls } = this; hls.on(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this); hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this); hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); } unregisterListener() { const { hls } = this; hls.off(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this); hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this); hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); } onFpsDropLevelCapping(event, data) { const level = this.hls.levels[data.droppedLevel]; if (this.isLevelAllowed(level)) this.restrictedLevels.push({ bitrate: level.bitrate, height: level.height, width: level.width }); } onMediaAttaching(event, data) { this.media = data.media instanceof HTMLVideoElement ? data.media : null; this.clientRect = null; if (this.timer && this.hls.levels.length) this.detectPlayerSize(); } onManifestParsed(event, data) { const hls = this.hls; this.restrictedLevels = []; this.firstLevel = data.firstLevel; if (hls.config.capLevelToPlayerSize && data.video) this.startCapping(); } onLevelsUpdated(event, data) { if (this.timer && isFiniteNumber(this.autoLevelCapping)) this.detectPlayerSize(); } onBufferCodecs(event, data) { if (this.hls.config.capLevelToPlayerSize && data.video) this.startCapping(); } onMediaDetaching() { this.stopCapping(); this.media = null; } detectPlayerSize() { if (this.media) { if (this.mediaHeight <= 0 || this.mediaWidth <= 0) { this.clientRect = null; return; } const levels = this.hls.levels; if (levels.length) { const hls = this.hls; const maxLevel = this.getMaxLevel(levels.length - 1); if (maxLevel !== this.autoLevelCapping) hls.logger.log(`Setting autoLevelCapping to ${maxLevel}: ${levels[maxLevel].height}p@${levels[maxLevel].bitrate} for media ${this.mediaWidth}x${this.mediaHeight}`); hls.autoLevelCapping = maxLevel; if (hls.autoLevelEnabled && hls.autoLevelCapping > this.autoLevelCapping && this.streamController) this.streamController.nextLevelSwitch(); this.autoLevelCapping = hls.autoLevelCapping; } } } getMaxLevel(capLevelIndex) { const levels = this.hls.levels; if (!levels.length) return -1; const validLevels = levels.filter((level, index) => this.isLevelAllowed(level) && index <= capLevelIndex); this.clientRect = null; return CapLevelController.getMaxLevelByMediaSize(validLevels, this.mediaWidth, this.mediaHeight); } startCapping() { if (this.timer) return; this.autoLevelCapping = Number.POSITIVE_INFINITY; self.clearInterval(this.timer); this.timer = self.setInterval(this.detectPlayerSize.bind(this), 1e3); this.detectPlayerSize(); } stopCapping() { this.restrictedLevels = []; this.firstLevel = -1; this.autoLevelCapping = Number.POSITIVE_INFINITY; if (this.timer) { self.clearInterval(this.timer); this.timer = void 0; } } getDimensions() { if (this.clientRect) return this.clientRect; const media = this.media; const boundsRect = { width: 0, height: 0 }; if (media) { const clientRect = media.getBoundingClientRect(); boundsRect.width = clientRect.width; boundsRect.height = clientRect.height; if (!boundsRect.width && !boundsRect.height) { boundsRect.width = clientRect.right - clientRect.left || media.width || 0; boundsRect.height = clientRect.bottom - clientRect.top || media.height || 0; } } this.clientRect = boundsRect; return boundsRect; } get mediaWidth() { return this.getDimensions().width * this.contentScaleFactor; } get mediaHeight() { return this.getDimensions().height * this.contentScaleFactor; } get contentScaleFactor() { let pixelRatio = 1; if (!this.hls.config.ignoreDevicePixelRatio) try { pixelRatio = self.devicePixelRatio; } catch (e) {} return Math.min(pixelRatio, this.hls.config.maxDevicePixelRatio); } isLevelAllowed(level) { return !this.restrictedLevels.some((restrictedLevel) => { return level.bitrate === restrictedLevel.bitrate && level.width === restrictedLevel.width && level.height === restrictedLevel.height; }); } static getMaxLevelByMediaSize(levels, width, height) { if (!(levels != null && levels.length)) return -1; const atGreatestBandwidth = (curLevel, nextLevel) => { if (!nextLevel) return true; return curLevel.width !== nextLevel.width || curLevel.height !== nextLevel.height; }; let maxLevelIndex = levels.length - 1; const squareSize = Math.max(width, height); for (let i = 0; i < levels.length; i += 1) { const level = levels[i]; if ((level.width >= squareSize || level.height >= squareSize) && atGreatestBandwidth(level, levels[i + 1])) { maxLevelIndex = i; break; } } return maxLevelIndex; } }; /** * Common Media Client Data Object Type * * @group CMCD * * @beta * * @enum */ var CmcdObjectType = { /** * text file, such as a manifest or playlist */ MANIFEST: "m", /** * audio only */ AUDIO: "a", /** * video only */ VIDEO: "v", /** * muxed audio and video */ MUXED: "av", /** * init segment */ INIT: "i", /** * caption or subtitle */ CAPTION: "c", /** * ISOBMFF timed text track */ TIMED_TEXT: "tt", /** * cryptographic key, license or certificate. */ KEY: "k", /** * other */ OTHER: "o" }; /** * Common Media Client Data Streaming Format * * @group CMCD * * @enum * * @beta */ var CmcdStreamingFormat = { /** * HTTP Live Streaming (HLS) */ HLS: "h" }; /** * Structured Field Item * * @group Structured Field * * @beta */ var SfItem = class SfItem { constructor(value, params) { if (Array.isArray(value)) value = value.map((v) => v instanceof SfItem ? v : new SfItem(v)); this.value = value; this.params = params; } }; var DICT = "Dict"; function format(value) { if (Array.isArray(value)) return JSON.stringify(value); if (value instanceof Map) return "Map{}"; if (value instanceof Set) return "Set{}"; if (typeof value === "object") return JSON.stringify(value); return String(value); } function throwError(action, src, type, cause) { return new Error(`failed to ${action} "${format(src)}" as ${type}`, { cause }); } function serializeError(src, type, cause) { return throwError("serialize", src, type, cause); } /** * A class to represent structured field tokens when `Symbol` is not available. * * @group Structured Field * * @beta */ var SfToken = class { constructor(description) { this.description = description; } }; var BARE_ITEM = "Bare Item"; var BOOLEAN = "Boolean"; function serializeBoolean(value) { if (typeof value !== "boolean") throw serializeError(value, BOOLEAN); return value ? "?1" : "?0"; } /** * Encodes binary data to base64 * * @param binary - The binary data to encode * @returns The base64 encoded string * * @group Utils * * @beta */ function encodeBase64(binary) { return btoa(String.fromCharCode(...binary)); } var BYTES = "Byte Sequence"; function serializeByteSequence(value) { if (ArrayBuffer.isView(value) === false) throw serializeError(value, BYTES); return `:${encodeBase64(value)}:`; } var INTEGER = "Integer"; function isInvalidInt(value) { return value < -999999999999999 || 999999999999999 < value; } function serializeInteger(value) { if (isInvalidInt(value)) throw serializeError(value, INTEGER); return value.toString(); } function serializeDate(value) { return `@${serializeInteger(value.getTime() / 1e3)}`; } /** * This implements the rounding procedure described in step 2 of the "Serializing a Decimal" specification. * This rounding style is known as "even rounding", "banker's rounding", or "commercial rounding". * * @param value - The value to round * @param precision - The number of decimal places to round to * @returns The rounded value * * @group Utils * * @beta */ function roundToEven(value, precision) { if (value < 0) return -roundToEven(-value, precision); const decimalShift = Math.pow(10, precision); if (Math.abs(value * decimalShift % 1 - .5) < Number.EPSILON) { const flooredValue = Math.floor(value * decimalShift); return (flooredValue % 2 === 0 ? flooredValue : flooredValue + 1) / decimalShift; } else return Math.round(value * decimalShift) / decimalShift; } var DECIMAL = "Decimal"; function serializeDecimal(value) { const roundedValue = roundToEven(value, 3); if (Math.floor(Math.abs(roundedValue)).toString().length > 12) throw serializeError(value, DECIMAL); const stringValue = roundedValue.toString(); return stringValue.includes(".") ? stringValue : `${stringValue}.0`; } var STRING = "String"; var STRING_REGEX = /[\x00-\x1f\x7f]+/; function serializeString(value) { if (STRING_REGEX.test(value)) throw serializeError(value, STRING); return `"${value.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`)}"`; } /** * Converts a symbol to a string. * * @param symbol - The symbol to convert. * * @returns The string representation of the symbol. * * @internal */ function symbolToStr(symbol) { return symbol.description || symbol.toString().slice(7, -1); } var TOKEN = "Token"; function serializeToken(token) { const value = symbolToStr(token); if (/^([a-zA-Z*])([!#$%&'*+\-.^_`|~\w:/]*)$/.test(value) === false) throw serializeError(value, TOKEN); return value; } function serializeBareItem(value) { switch (typeof value) { case "number": if (!isFiniteNumber(value)) throw serializeError(value, BARE_ITEM); if (Number.isInteger(value)) return serializeInteger(value); return serializeDecimal(value); case "string": return serializeString(value); case "symbol": return serializeToken(value); case "boolean": return serializeBoolean(value); case "object": if (value instanceof Date) return serializeDate(value); if (value instanceof Uint8Array) return serializeByteSequence(value); if (value instanceof SfToken) return serializeToken(value); default: throw serializeError(value, BARE_ITEM); } } var KEY = "Key"; function serializeKey(value) { if (/^[a-z*][a-z0-9\-_.*]*$/.test(value) === false) throw serializeError(value, KEY); return value; } function serializeParams(params) { if (params == null) return ""; return Object.entries(params).map(([key, value]) => { if (value === true) return `;${serializeKey(key)}`; return `;${serializeKey(key)}=${serializeBareItem(value)}`; }).join(""); } function serializeItem(value) { if (value instanceof SfItem) return `${serializeBareItem(value.value)}${serializeParams(value.params)}`; else return serializeBareItem(value); } function serializeInnerList(value) { return `(${value.value.map(serializeItem).join(" ")})${serializeParams(value.params)}`; } function serializeDict(dict, options = { whitespace: true }) { if (typeof dict !== "object" || dict == null) throw serializeError(dict, DICT); const entries = dict instanceof Map ? dict.entries() : Object.entries(dict); const optionalWhiteSpace = (options === null || options === void 0 ? void 0 : options.whitespace) ? " " : ""; return Array.from(entries).map(([key, item]) => { if (item instanceof SfItem === false) item = new SfItem(item); let output = serializeKey(key); if (item.value === true) output += serializeParams(item.params); else { output += "="; if (Array.isArray(item.value)) output += serializeInnerList(item); else output += serializeItem(item); } return output; }).join(`,${optionalWhiteSpace}`); } /** * Encode an object into a structured field dictionary * * @param value - The structured field dictionary to encode * @param options - Encoding options * * @returns The structured field string * * @group Structured Field * * @beta */ function encodeSfDict(value, options) { return serializeDict(value, options); } /** * CMCD object header name. * * @group CMCD * * @beta */ var CMCD_OBJECT = "CMCD-Object"; /** * CMCD request header name. * * @group CMCD * * @beta */ var CMCD_REQUEST = "CMCD-Request"; /** * CMCD session header name. * * @group CMCD * * @beta */ var CMCD_SESSION = "CMCD-Session"; /** * CMCD status header name. * * @group CMCD * * @beta */ var CMCD_STATUS = "CMCD-Status"; /** * The map of CMCD keys to their appropriate header shard. * * @group CMCD * * @internal */ var CMCD_HEADER_MAP = { br: CMCD_OBJECT, ab: CMCD_OBJECT, d: CMCD_OBJECT, ot: CMCD_OBJECT, tb: CMCD_OBJECT, tpb: CMCD_OBJECT, lb: CMCD_OBJECT, tab: CMCD_OBJECT, lab: CMCD_OBJECT, url: CMCD_OBJECT, pb: CMCD_REQUEST, bl: CMCD_REQUEST, tbl: CMCD_REQUEST, dl: CMCD_REQUEST, ltc: CMCD_REQUEST, mtp: CMCD_REQUEST, nor: CMCD_REQUEST, nrr: CMCD_REQUEST, rc: CMCD_REQUEST, sn: CMCD_REQUEST, sta: CMCD_REQUEST, su: CMCD_REQUEST, ttfb: CMCD_REQUEST, ttfbb: CMCD_REQUEST, ttlb: CMCD_REQUEST, cmsdd: CMCD_REQUEST, cmsds: CMCD_REQUEST, smrt: CMCD_REQUEST, df: CMCD_REQUEST, cs: CMCD_REQUEST, ts: CMCD_REQUEST, cid: CMCD_SESSION, pr: CMCD_SESSION, sf: CMCD_SESSION, sid: CMCD_SESSION, st: CMCD_SESSION, v: CMCD_SESSION, msd: CMCD_SESSION, bs: CMCD_STATUS, bsd: CMCD_STATUS, cdn: CMCD_STATUS, rtp: CMCD_STATUS, bg: CMCD_STATUS, pt: CMCD_STATUS, ec: CMCD_STATUS, e: CMCD_STATUS }; /** * CMCD header fields. * * @group CMCD * * @enum * * @beta */ var CmcdHeaderField = { /** * keys whose values vary with each request. */ REQUEST: CMCD_REQUEST }; function createHeaderMap(headerMap) { return Object.keys(headerMap).reduce((acc, field) => { var _a; (_a = headerMap[field]) === null || _a === void 0 || _a.forEach((key) => acc[key] = field); return acc; }, {}); } /** * Group a CMCD data object into header shards * * @param cmcd - The CMCD data object to convert. * @param customHeaderMap - A map of CMCD header fields to custom CMCD keys. * * @returns The CMCD header shards. * * @group CMCD * * @beta */ function groupCmcdHeaders(cmcd, customHeaderMap) { const result = {}; if (!cmcd) return result; const keys = Object.keys(cmcd); const custom = customHeaderMap ? createHeaderMap(customHeaderMap) : {}; return keys.reduce((acc, key) => { var _a; const field = CMCD_HEADER_MAP[key] || custom[key] || CmcdHeaderField.REQUEST; const data = (_a = acc[field]) !== null && _a !== void 0 ? _a : acc[field] = {}; data[key] = cmcd[key]; return acc; }, result); } /** * Checks if the given key is a token field. * * @param key - The key to check. * * @returns `true` if the key is a token field. * * @internal */ function isTokenField(key) { return [ "ot", "sf", "st", "e", "sta" ].includes(key); } /** * Checks if the given value is valid * * @param value - The value to check. * * @returns `true` if the key is a value is valid. * * @internal */ function isValid(value) { if (typeof value === "number") return isFiniteNumber(value); return value != null && value !== "" && value !== false; } /** * CMCD event mode variable name. * * @group CMCD * * @beta */ var CMCD_EVENT_MODE = "event"; /** * Constructs a relative path from a URL. * * @param url - The destination URL * @param base - The base URL * @returns The relative path * * @group Utils * * @beta */ function urlToRelativePath(url, base) { const to = new URL(url); const from = new URL(base); if (to.origin !== from.origin) return url; const toPath = to.pathname.split("/").slice(1); const fromPath = from.pathname.split("/").slice(1, -1); while (toPath[0] === fromPath[0]) { toPath.shift(); fromPath.shift(); } while (fromPath.length) { fromPath.shift(); toPath.unshift(".."); } return toPath.join("/") + to.search + to.hash; } var toRounded = (value) => Math.round(value); var toUrlSafe = (value, options) => { if (Array.isArray(value)) return value.map((item) => toUrlSafe(item, options)); if (value instanceof SfItem && typeof value.value === "string") return new SfItem(toUrlSafe(value.value, options), value.params); else { if (options.baseUrl) value = urlToRelativePath(value, options.baseUrl); return options.version === 1 ? encodeURIComponent(value) : value; } }; var toHundred = (value) => toRounded(value / 100) * 100; var nor = (value, options) => { let norValue = value; if (options.version >= 2) { if (value instanceof SfItem && typeof value.value === "string") norValue = new SfItem([value]); else if (typeof value === "string") norValue = [value]; } return toUrlSafe(norValue, options); }; /** * The default formatters for CMCD values. * * @group CMCD * * @beta */ var CMCD_FORMATTER_MAP = { /** * Bitrate (kbps) rounded integer */ br: toRounded, /** * Duration (milliseconds) rounded integer */ d: toRounded, /** * Buffer Length (milliseconds) rounded nearest 100ms */ bl: toHundred, /** * Deadline (milliseconds) rounded nearest 100ms */ dl: toHundred, /** * Measured Throughput (kbps) rounded nearest 100kbps */ mtp: toHundred, /** * Next Object Request URL encoded */ nor, /** * Requested maximum throughput (kbps) rounded nearest 100kbps */ rtp: toHundred, /** * Top Bitrate (kbps) rounded integer */ tb: toRounded }; /** * CMCD request mode variable name. * * @group CMCD * * @beta */ var CMCD_REQUEST_MODE = "request"; /** * CMCD response mode variable name. * * @group CMCD * * @beta */ var CMCD_RESPONSE_MODE = "response"; /** * Defines the common keys for CMCD (Common Media Client Data) version 2. * * @group CMCD * * @beta */ var CMCD_COMMON_KEYS = [ "ab", "bg", "bl", "br", "bs", "bsd", "cdn", "cid", "cs", "df", "ec", "lab", "lb", "ltc", "msd", "mtp", "pb", "pr", "pt", "sf", "sid", "sn", "st", "sta", "tab", "tb", "tbl", "tpb", "ts", "v" ]; /** * Defines the event-specific keys for CMCD (Common Media Client Data) version 2. * * @group CMCD * * @beta */ var CMCD_EVENT_KEYS = ["e"]; var CUSTOM_KEY_REGEX = /^[a-zA-Z0-9-.]+-[a-zA-Z0-9-.]+$/; /** * Check if a key is a custom key. * * @param key - The key to check. * * @returns `true` if the key is a custom key, `false` otherwise. * * @group CMCD * * @beta */ function isCmcdCustomKey(key) { return CUSTOM_KEY_REGEX.test(key); } /** * Check if a key is a valid CMCD event key. * * @param key - The key to check. * * @returns `true` if the key is a valid CMCD event key, `false` otherwise. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/isCmcdEventKey.test.ts#example} */ function isCmcdEventKey(key) { return CMCD_COMMON_KEYS.includes(key) || CMCD_EVENT_KEYS.includes(key) || isCmcdCustomKey(key); } /** * Defines the request-specific keys for CMCD (Common Media Client Data) version 2. * * @group CMCD * * @beta */ var CMCD_REQUEST_KEYS = [ "d", "dl", "nor", "ot", "rtp", "su" ]; /** * Check if a key is a valid CMCD request key. * * @param key - The key to check. * * @returns `true` if the key is a valid CMCD request key, `false` otherwise. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/isCmcdRequestKey.test.ts#example} */ function isCmcdRequestKey(key) { return CMCD_COMMON_KEYS.includes(key) || CMCD_REQUEST_KEYS.includes(key) || isCmcdCustomKey(key); } /** * CMCD v2 - Response-only and timing keys. * * @group CMCD * * @beta */ var CMCD_RESPONSE_KEYS = [ "cmsdd", "cmsds", "rc", "smrt", "ttfb", "ttfbb", "ttlb", "url" ]; /** * Check if a key is a valid CMCD response key. * * @param key - The key to check. * * @returns `true` if the key is a valid CMCD request key, `false` otherwise. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/isCmcdResponseKey.test.ts#example} */ function isCmcdResponseKey(key) { return CMCD_COMMON_KEYS.includes(key) || CMCD_REQUEST_KEYS.includes(key) || CMCD_RESPONSE_KEYS.includes(key) || isCmcdCustomKey(key); } /** * Defines the keys for CMCD (Common Media Client Data) version 1. * * @group CMCD * * @beta */ var CMCD_V1_KEYS = [ "bl", "br", "bs", "cid", "d", "dl", "mtp", "nor", "nrr", "ot", "pr", "rtp", "sf", "sid", "st", "su", "tb", "v" ]; /** * Filter function for CMCD v1 keys. * * @param key - The CMCD key to filter. * * @returns `true` if the key should be included, `false` otherwise. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/isCmcdV1Key.test.ts#example} */ function isCmcdV1Key(key) { return CMCD_V1_KEYS.includes(key) || isCmcdCustomKey(key); } var filterMap = { [CMCD_RESPONSE_MODE]: isCmcdResponseKey, [CMCD_EVENT_MODE]: isCmcdEventKey, [CMCD_REQUEST_MODE]: isCmcdRequestKey }; /** * Convert a generic object to CMCD data. * * @param obj - The CMCD object to process. * @param options - Options for encoding. * * @group CMCD * * @beta */ function prepareCmcdData(obj, options = {}) { const results = {}; if (obj == null || typeof obj !== "object") return results; const version = options.version || obj["v"] || 1; const reportingMode = options.reportingMode || CMCD_REQUEST_MODE; const keyFilter = version === 1 ? isCmcdV1Key : filterMap[reportingMode]; let keys = Object.keys(obj).filter(keyFilter); const filter = options.filter; if (typeof filter === "function") keys = keys.filter(filter); const needsTimestamp = reportingMode === CMCD_RESPONSE_MODE || reportingMode === CMCD_EVENT_MODE; if (needsTimestamp && !keys.includes("ts")) keys.push("ts"); if (version > 1 && !keys.includes("v")) keys.push("v"); const formatters = _extends({}, CMCD_FORMATTER_MAP, options.formatters); const formatterOptions = { version, reportingMode, baseUrl: options.baseUrl }; keys.sort().forEach((key) => { let value = obj[key]; const formatter = formatters[key]; if (typeof formatter === "function") value = formatter(value, formatterOptions); if (key === "v") if (version === 1) return; else value = version; if (key == "pr" && value === 1) return; if (needsTimestamp && key === "ts" && !isFiniteNumber(value)) value = Date.now(); if (!isValid(value)) return; if (isTokenField(key) && typeof value === "string") value = new SfToken(value); results[key] = value; }); return results; } /** * Convert a CMCD data object to request headers * * @param cmcd - The CMCD data object to convert. * @param options - Options for encoding the CMCD object. * * @returns The CMCD header shards. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/toCmcdHeaders.test.ts#example} */ function toCmcdHeaders(cmcd, options = {}) { const result = {}; if (!cmcd) return result; const shards = groupCmcdHeaders(prepareCmcdData(cmcd, options), options === null || options === void 0 ? void 0 : options.customHeaderMap); return Object.entries(shards).reduce((acc, [field, value]) => { const shard = encodeSfDict(value, { whitespace: false }); if (shard) acc[field] = shard; return acc; }, result); } /** * Append CMCD query args to a header object. * * @param headers - The headers to append to. * @param cmcd - The CMCD object to append. * @param options - Encode options. * * @returns The headers with the CMCD header shards appended. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/appendCmcdHeaders.test.ts#example} */ function appendCmcdHeaders(headers, cmcd, options) { return _extends(headers, toCmcdHeaders(cmcd, options)); } /** * CMCD parameter name. * * @group CMCD * * @beta */ var CMCD_PARAM = "CMCD"; /** * Encode a CMCD object to a string. * * @param cmcd - The CMCD object to encode. * @param options - Options for encoding. * * @returns The encoded CMCD string. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/encodeCmcd.test.ts#example} */ function encodeCmcd(cmcd, options = {}) { if (!cmcd) return ""; return encodeSfDict(prepareCmcdData(cmcd, options), { whitespace: false }); } /** * Convert a CMCD data object to a URL encoded string. * * @param cmcd - The CMCD object to convert. * @param options - Options for encoding the CMCD object. * * @returns The URL encoded CMCD data. * * @group CMCD * * @beta */ function toCmcdUrl(cmcd, options = {}) { if (!cmcd) return ""; const params = encodeCmcd(cmcd, options); return encodeURIComponent(params); } /** * Convert a CMCD data object to a query arg. * * @param cmcd - The CMCD object to convert. * @param options - Options for encoding the CMCD object. * * @returns The CMCD query arg. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/toCmcdQuery.test.ts#example} */ function toCmcdQuery(cmcd, options = {}) { if (!cmcd) return ""; return `${CMCD_PARAM}=${toCmcdUrl(cmcd, options)}`; } var REGEX = /CMCD=[^&#]+/; /** * Append CMCD query args to a URL. * * @param url - The URL to append to. * @param cmcd - The CMCD object to append. * @param options - Options for encoding the CMCD object. * * @returns The URL with the CMCD query args appended. * * @group CMCD * * @beta * * @example * {@includeCode ../../test/cmcd/appendCmcdQuery.test.ts#example} */ function appendCmcdQuery(url, cmcd, options) { const query = toCmcdQuery(cmcd, options); if (!query) return url; if (REGEX.test(url)) return url.replace(REGEX, query); return `${url}${url.includes("?") ? "&" : "?"}${query}`; } /** * Controller to deal with Common Media Client Data (CMCD) * @see https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5004-final.pdf */ var CMCDController = class { constructor(hls) { this.hls = void 0; this.config = void 0; this.media = void 0; this.sid = void 0; this.cid = void 0; this.useHeaders = false; this.includeKeys = void 0; this.initialized = false; this.starved = false; this.buffering = true; this.audioBuffer = void 0; this.videoBuffer = void 0; this.onWaiting = () => { if (this.initialized) this.starved = true; this.buffering = true; }; this.onPlaying = () => { if (!this.initialized) this.initialized = true; this.buffering = false; }; /** * Apply CMCD data to a manifest request. */ this.applyPlaylistData = (context) => { try { this.apply(context, { ot: CmcdObjectType.MANIFEST, su: !this.initialized }); } catch (error) { this.hls.logger.warn("Could not generate manifest CMCD data.", error); } }; /** * Apply CMCD data to a segment request */ this.applyFragmentData = (context) => { try { const { frag, part } = context; const level = this.hls.levels[frag.level]; const ot = this.getObjectType(frag); const data = { d: (part || frag).duration * 1e3, ot }; if (ot === CmcdObjectType.VIDEO || ot === CmcdObjectType.AUDIO || ot == CmcdObjectType.MUXED) { data.br = level.bitrate / 1e3; data.tb = this.getTopBandwidth(ot) / 1e3; data.bl = this.getBufferLength(ot); } const next = part ? this.getNextPart(part) : this.getNextFrag(frag); if (next != null && next.url && next.url !== frag.url) data.nor = next.url; this.apply(context, data); } catch (error) { this.hls.logger.warn("Could not generate segment CMCD data.", error); } }; this.hls = hls; const config = this.config = hls.config; const { cmcd } = config; if (cmcd != null) { config.pLoader = this.createPlaylistLoader(); config.fLoader = this.createFragmentLoader(); this.sid = cmcd.sessionId || hls.sessionId; this.cid = cmcd.contentId; this.useHeaders = cmcd.useHeaders === true; this.includeKeys = cmcd.includeKeys; this.registerListeners(); } } registerListeners() { const hls = this.hls; hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.on(Events.MEDIA_DETACHED, this.onMediaDetached, this); hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this); } unregisterListeners() { const hls = this.hls; hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.off(Events.MEDIA_DETACHED, this.onMediaDetached, this); hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this); } destroy() { this.unregisterListeners(); this.onMediaDetached(); this.hls = this.config = this.audioBuffer = this.videoBuffer = null; this.onWaiting = this.onPlaying = this.media = null; } onMediaAttached(event, data) { this.media = data.media; this.media.addEventListener("waiting", this.onWaiting); this.media.addEventListener("playing", this.onPlaying); } onMediaDetached() { if (!this.media) return; this.media.removeEventListener("waiting", this.onWaiting); this.media.removeEventListener("playing", this.onPlaying); this.media = null; } onBufferCreated(event, data) { var _data$tracks$audio, _data$tracks$video; this.audioBuffer = (_data$tracks$audio = data.tracks.audio) == null ? void 0 : _data$tracks$audio.buffer; this.videoBuffer = (_data$tracks$video = data.tracks.video) == null ? void 0 : _data$tracks$video.buffer; } /** * Create baseline CMCD data */ createData() { var _this$media; return { v: 1, sf: CmcdStreamingFormat.HLS, sid: this.sid, cid: this.cid, pr: (_this$media = this.media) == null ? void 0 : _this$media.playbackRate, mtp: this.hls.bandwidthEstimate / 1e3 }; } /** * Apply CMCD data to a request. */ apply(context, data = {}) { _extends(data, this.createData()); const isVideo = data.ot === CmcdObjectType.INIT || data.ot === CmcdObjectType.VIDEO || data.ot === CmcdObjectType.MUXED; if (this.starved && isVideo) { data.bs = true; data.su = true; this.starved = false; } if (data.su == null) data.su = this.buffering; const { includeKeys } = this; if (includeKeys) data = Object.keys(data).reduce((acc, key) => { includeKeys.includes(key) && (acc[key] = data[key]); return acc; }, {}); const options = { baseUrl: context.url }; if (this.useHeaders) { if (!context.headers) context.headers = {}; appendCmcdHeaders(context.headers, data, options); } else context.url = appendCmcdQuery(context.url, data, options); } getNextFrag(fragment) { var _this$hls$levels$frag; const levelDetails = (_this$hls$levels$frag = this.hls.levels[fragment.level]) == null ? void 0 : _this$hls$levels$frag.details; if (levelDetails) { const index = fragment.sn - levelDetails.startSN; return levelDetails.fragments[index + 1]; } } getNextPart(part) { var _this$hls$levels$frag2; const { index, fragment } = part; const partList = (_this$hls$levels$frag2 = this.hls.levels[fragment.level]) == null || (_this$hls$levels$frag2 = _this$hls$levels$frag2.details) == null ? void 0 : _this$hls$levels$frag2.partList; if (partList) { const { sn } = fragment; for (let i = partList.length - 1; i >= 0; i--) { const p = partList[i]; if (p.index === index && p.fragment.sn === sn) return partList[i + 1]; } } } /** * The CMCD object type. */ getObjectType(fragment) { const { type } = fragment; if (type === "subtitle") return CmcdObjectType.TIMED_TEXT; if (fragment.sn === "initSegment") return CmcdObjectType.INIT; if (type === "audio") return CmcdObjectType.AUDIO; if (type === "main") { if (!this.hls.audioTracks.length) return CmcdObjectType.MUXED; return CmcdObjectType.VIDEO; } } /** * Get the highest bitrate. */ getTopBandwidth(type) { let bitrate = 0; let levels; const hls = this.hls; if (type === CmcdObjectType.AUDIO) levels = hls.audioTracks; else { const max = hls.maxAutoLevel; const len = max > -1 ? max + 1 : hls.levels.length; levels = hls.levels.slice(0, len); } levels.forEach((level) => { if (level.bitrate > bitrate) bitrate = level.bitrate; }); return bitrate > 0 ? bitrate : NaN; } /** * Get the buffer length for a media type in milliseconds */ getBufferLength(type) { const media = this.media; const buffer = type === CmcdObjectType.AUDIO ? this.audioBuffer : this.videoBuffer; if (!buffer || !media) return NaN; return BufferHelper.bufferInfo(buffer, media.currentTime, this.config.maxBufferHole).len * 1e3; } /** * Create a playlist loader */ createPlaylistLoader() { const { pLoader } = this.config; const apply = this.applyPlaylistData; const Ctor = pLoader || this.config.loader; return class CmcdPlaylistLoader { constructor(config) { this.loader = void 0; this.loader = new Ctor(config); } get stats() { return this.loader.stats; } get context() { return this.loader.context; } destroy() { this.loader.destroy(); } abort() { this.loader.abort(); } load(context, config, callbacks) { apply(context); this.loader.load(context, config, callbacks); } }; } /** * Create a playlist loader */ createFragmentLoader() { const { fLoader } = this.config; const apply = this.applyFragmentData; const Ctor = fLoader || this.config.loader; return class CmcdFragmentLoader { constructor(config) { this.loader = void 0; this.loader = new Ctor(config); } get stats() { return this.loader.stats; } get context() { return this.loader.context; } destroy() { this.loader.destroy(); } abort() { this.loader.abort(); } load(context, config, callbacks) { apply(context); this.loader.load(context, config, callbacks); } }; } }; var PATHWAY_PENALTY_DURATION_MS = 3e5; var ContentSteeringController = class extends Logger { constructor(hls) { super("content-steering", hls.logger); this.hls = void 0; this.loader = null; this.uri = null; this.pathwayId = "."; this._pathwayPriority = null; this.timeToLoad = 300; this.reloadTimer = -1; this.updated = 0; this.started = false; this.enabled = true; this.levels = null; this.audioTracks = null; this.subtitleTracks = null; this.penalizedPathways = {}; this.hls = hls; this.registerListeners(); } registerListeners() { const hls = this.hls; hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const hls = this.hls; if (!hls) return; hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.off(Events.ERROR, this.onError, this); } pathways() { return (this.levels || []).reduce((pathways, level) => { if (pathways.indexOf(level.pathwayId) === -1) pathways.push(level.pathwayId); return pathways; }, []); } get pathwayPriority() { return this._pathwayPriority; } set pathwayPriority(pathwayPriority) { this.updatePathwayPriority(pathwayPriority); } startLoad() { this.started = true; this.clearTimeout(); if (this.enabled && this.uri) { if (this.updated) { const ttl = this.timeToLoad * 1e3 - (performance.now() - this.updated); if (ttl > 0) { this.scheduleRefresh(this.uri, ttl); return; } } this.loadSteeringManifest(this.uri); } } stopLoad() { this.started = false; if (this.loader) { this.loader.destroy(); this.loader = null; } this.clearTimeout(); } clearTimeout() { if (this.reloadTimer !== -1) { self.clearTimeout(this.reloadTimer); this.reloadTimer = -1; } } destroy() { this.unregisterListeners(); this.stopLoad(); this.hls = null; this.levels = this.audioTracks = this.subtitleTracks = null; } removeLevel(levelToRemove) { const levels = this.levels; if (levels) this.levels = levels.filter((level) => level !== levelToRemove); } onManifestLoading() { this.stopLoad(); this.enabled = true; this.timeToLoad = 300; this.updated = 0; this.uri = null; this.pathwayId = "."; this.levels = this.audioTracks = this.subtitleTracks = null; } onManifestLoaded(event, data) { const { contentSteering } = data; if (contentSteering === null) return; this.pathwayId = contentSteering.pathwayId; this.uri = contentSteering.uri; if (this.started) this.startLoad(); } onManifestParsed(event, data) { this.audioTracks = data.audioTracks; this.subtitleTracks = data.subtitleTracks; } onError(event, data) { const { errorAction } = data; if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox && errorAction.flags === ErrorActionFlags.MoveAllAlternatesMatchingHost) { const levels = this.levels; let pathwayPriority = this._pathwayPriority; let errorPathway = this.pathwayId; if (data.context) { const { groupId, pathwayId, type } = data.context; if (groupId && levels) errorPathway = this.getPathwayForGroupId(groupId, type, errorPathway); else if (pathwayId) errorPathway = pathwayId; } if (!(errorPathway in this.penalizedPathways)) this.penalizedPathways[errorPathway] = performance.now(); if (!pathwayPriority && levels) pathwayPriority = this.pathways(); if (pathwayPriority && pathwayPriority.length > 1) { this.updatePathwayPriority(pathwayPriority); errorAction.resolved = this.pathwayId !== errorPathway; } if (data.details === ErrorDetails.BUFFER_APPEND_ERROR && !data.fatal) errorAction.resolved = true; else if (!errorAction.resolved) this.warn(`Could not resolve ${data.details} ("${data.error.message}") with content-steering for Pathway: ${errorPathway} levels: ${levels ? levels.length : levels} priorities: ${stringify(pathwayPriority)} penalized: ${stringify(this.penalizedPathways)}`); } } filterParsedLevels(levels) { this.levels = levels; let pathwayLevels = this.getLevelsForPathway(this.pathwayId); if (pathwayLevels.length === 0) { const pathwayId = levels[0].pathwayId; this.log(`No levels found in Pathway ${this.pathwayId}. Setting initial Pathway to "${pathwayId}"`); pathwayLevels = this.getLevelsForPathway(pathwayId); this.pathwayId = pathwayId; } if (pathwayLevels.length !== levels.length) this.log(`Found ${pathwayLevels.length}/${levels.length} levels in Pathway "${this.pathwayId}"`); return pathwayLevels; } getLevelsForPathway(pathwayId) { if (this.levels === null) return []; return this.levels.filter((level) => pathwayId === level.pathwayId); } updatePathwayPriority(pathwayPriority) { this._pathwayPriority = pathwayPriority; let levels; const penalizedPathways = this.penalizedPathways; const now = performance.now(); Object.keys(penalizedPathways).forEach((pathwayId) => { if (now - penalizedPathways[pathwayId] > PATHWAY_PENALTY_DURATION_MS) delete penalizedPathways[pathwayId]; }); for (let i = 0; i < pathwayPriority.length; i++) { const pathwayId = pathwayPriority[i]; if (pathwayId in penalizedPathways) continue; if (pathwayId === this.pathwayId) return; const selectedIndex = this.hls.nextLoadLevel; const selectedLevel = this.hls.levels[selectedIndex]; levels = this.getLevelsForPathway(pathwayId); if (levels.length > 0) { this.log(`Setting Pathway to "${pathwayId}"`); this.pathwayId = pathwayId; reassignFragmentLevelIndexes(levels); this.hls.trigger(Events.LEVELS_UPDATED, { levels }); const levelAfterChange = this.hls.levels[selectedIndex]; if (selectedLevel && levelAfterChange && this.levels) { if (levelAfterChange.attrs["STABLE-VARIANT-ID"] !== selectedLevel.attrs["STABLE-VARIANT-ID"] && levelAfterChange.bitrate !== selectedLevel.bitrate) this.log(`Unstable Pathways change from bitrate ${selectedLevel.bitrate} to ${levelAfterChange.bitrate}`); this.hls.nextLoadLevel = selectedIndex; } break; } } } getPathwayForGroupId(groupId, type, defaultPathway) { const levels = this.getLevelsForPathway(defaultPathway).concat(this.levels || []); for (let i = 0; i < levels.length; i++) if (type === PlaylistContextType.AUDIO_TRACK && levels[i].hasAudioGroup(groupId) || type === PlaylistContextType.SUBTITLE_TRACK && levels[i].hasSubtitleGroup(groupId)) return levels[i].pathwayId; return defaultPathway; } clonePathways(pathwayClones) { const levels = this.levels; if (!levels) return; const audioGroupCloneMap = {}; const subtitleGroupCloneMap = {}; pathwayClones.forEach((pathwayClone) => { const { ID: cloneId, "BASE-ID": baseId, "URI-REPLACEMENT": uriReplacement } = pathwayClone; if (levels.some((level) => level.pathwayId === cloneId)) return; const clonedVariants = this.getLevelsForPathway(baseId).map((baseLevel) => { const attributes = new AttrList(baseLevel.attrs); attributes["PATHWAY-ID"] = cloneId; const clonedAudioGroupId = attributes.AUDIO && `${attributes.AUDIO}_clone_${cloneId}`; const clonedSubtitleGroupId = attributes.SUBTITLES && `${attributes.SUBTITLES}_clone_${cloneId}`; if (clonedAudioGroupId) { audioGroupCloneMap[attributes.AUDIO] = clonedAudioGroupId; attributes.AUDIO = clonedAudioGroupId; } if (clonedSubtitleGroupId) { subtitleGroupCloneMap[attributes.SUBTITLES] = clonedSubtitleGroupId; attributes.SUBTITLES = clonedSubtitleGroupId; } const url = performUriReplacement(baseLevel.uri, attributes["STABLE-VARIANT-ID"], "PER-VARIANT-URIS", uriReplacement); const clonedLevel = new Level({ attrs: attributes, audioCodec: baseLevel.audioCodec, bitrate: baseLevel.bitrate, height: baseLevel.height, name: baseLevel.name, url, videoCodec: baseLevel.videoCodec, width: baseLevel.width }); if (baseLevel.audioGroups) for (let i = 1; i < baseLevel.audioGroups.length; i++) clonedLevel.addGroupId("audio", `${baseLevel.audioGroups[i]}_clone_${cloneId}`); if (baseLevel.subtitleGroups) for (let i = 1; i < baseLevel.subtitleGroups.length; i++) clonedLevel.addGroupId("text", `${baseLevel.subtitleGroups[i]}_clone_${cloneId}`); return clonedLevel; }); levels.push(...clonedVariants); cloneRenditionGroups(this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId); cloneRenditionGroups(this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId); }); } loadSteeringManifest(uri) { const config = this.hls.config; const Loader = config.loader; if (this.loader) this.loader.destroy(); this.loader = new Loader(config); let url; try { url = new self.URL(uri); } catch (error) { this.enabled = false; this.log(`Failed to parse Steering Manifest URI: ${uri}`); return; } if (url.protocol !== "data:") { const throughput = (this.hls.bandwidthEstimate || config.abrEwmaDefaultEstimate) | 0; url.searchParams.set("_HLS_pathway", this.pathwayId); url.searchParams.set("_HLS_throughput", "" + throughput); } const context = { responseType: "json", url: url.href }; const loadPolicy = config.steeringManifestLoadPolicy.default; const legacyRetryCompatibility = loadPolicy.errorRetry || loadPolicy.timeoutRetry || {}; const loaderConfig = { loadPolicy, timeout: loadPolicy.maxLoadTimeMs, maxRetry: legacyRetryCompatibility.maxNumRetry || 0, retryDelay: legacyRetryCompatibility.retryDelayMs || 0, maxRetryDelay: legacyRetryCompatibility.maxRetryDelayMs || 0 }; const callbacks = { onSuccess: (response, stats, context, networkDetails) => { this.log(`Loaded steering manifest: "${url}"`); const steeringData = response.data; if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) { this.log(`Steering VERSION ${steeringData.VERSION} not supported!`); return; } this.updated = performance.now(); this.timeToLoad = steeringData.TTL; const { "RELOAD-URI": reloadUri, "PATHWAY-CLONES": pathwayClones, "PATHWAY-PRIORITY": pathwayPriority } = steeringData; if (reloadUri) try { this.uri = new self.URL(reloadUri, url).href; } catch (error) { this.enabled = false; this.log(`Failed to parse Steering Manifest RELOAD-URI: ${reloadUri}`); return; } this.scheduleRefresh(this.uri || context.url); if (pathwayClones) this.clonePathways(pathwayClones); const loadedSteeringData = { steeringManifest: steeringData, url: url.toString() }; this.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData); if (pathwayPriority) this.updatePathwayPriority(pathwayPriority); }, onError: (error, context, networkDetails, stats) => { this.log(`Error loading steering manifest: ${error.code} ${error.text} (${context.url})`); this.stopLoad(); if (error.code === 410) { this.enabled = false; this.log(`Steering manifest ${context.url} no longer available`); return; } let ttl = this.timeToLoad * 1e3; if (error.code === 429) { const loader = this.loader; if (typeof (loader == null ? void 0 : loader.getResponseHeader) === "function") { const retryAfter = loader.getResponseHeader("Retry-After"); if (retryAfter) ttl = parseFloat(retryAfter) * 1e3; } this.log(`Steering manifest ${context.url} rate limited`); return; } this.scheduleRefresh(this.uri || context.url, ttl); }, onTimeout: (stats, context, networkDetails) => { this.log(`Timeout loading steering manifest (${context.url})`); this.scheduleRefresh(this.uri || context.url); } }; this.log(`Requesting steering manifest: ${url}`); this.loader.load(context, loaderConfig, callbacks); } scheduleRefresh(uri, ttlMs = this.timeToLoad * 1e3) { this.clearTimeout(); this.reloadTimer = self.setTimeout(() => { var _this$hls; const media = (_this$hls = this.hls) == null ? void 0 : _this$hls.media; if (media && !media.ended) { this.loadSteeringManifest(uri); return; } this.scheduleRefresh(uri, this.timeToLoad * 1e3); }, ttlMs); } }; function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) { if (!tracks) return; Object.keys(groupCloneMap).forEach((audioGroupId) => { const clonedTracks = tracks.filter((track) => track.groupId === audioGroupId).map((track) => { const clonedTrack = _extends({}, track); clonedTrack.details = void 0; clonedTrack.attrs = new AttrList(clonedTrack.attrs); clonedTrack.url = clonedTrack.attrs.URI = performUriReplacement(track.url, track.attrs["STABLE-RENDITION-ID"], "PER-RENDITION-URIS", uriReplacement); clonedTrack.groupId = clonedTrack.attrs["GROUP-ID"] = groupCloneMap[audioGroupId]; clonedTrack.attrs["PATHWAY-ID"] = cloneId; return clonedTrack; }); tracks.push(...clonedTracks); }); } function performUriReplacement(uri, stableId, perOptionKey, uriReplacement) { const { HOST: host, PARAMS: params, [perOptionKey]: perOptionUris } = uriReplacement; let perVariantUri; if (stableId) { perVariantUri = perOptionUris == null ? void 0 : perOptionUris[stableId]; if (perVariantUri) uri = perVariantUri; } const url = new self.URL(uri); if (host && !perVariantUri) url.host = host; if (params) Object.keys(params).sort().forEach((key) => { if (key) url.searchParams.set(key, params[key]); }); return url.href; } /** * Controller to deal with encrypted media extensions (EME) * @see https://developer.mozilla.org/en-US/docs/Web/API/Encrypted_Media_Extensions_API * * @class * @constructor */ var EMEController = class EMEController extends Logger { constructor(hls) { super("eme", hls.logger); this.hls = void 0; this.config = void 0; this.media = null; this.mediaResolved = void 0; this.keyFormatPromise = null; this.keySystemAccessPromises = {}; this._requestLicenseFailureCount = 0; this.mediaKeySessions = []; this.keyIdToKeySessionPromise = {}; this.mediaKeys = null; this.setMediaKeysQueue = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : []; this.bannedKeyIds = {}; this.onMediaEncrypted = (event) => { const { initDataType, initData } = event; const logMessage = `"${event.type}" event: init data type: "${initDataType}"`; this.debug(logMessage); if (initData === null) return; if (!this.keyFormatPromise) { let keySystems = Object.keys(this.keySystemAccessPromises); if (!keySystems.length) keySystems = getKeySystemsForConfig(this.config); const keyFormats = keySystems.map(keySystemDomainToKeySystemFormat).filter((k) => !!k); this.keyFormatPromise = this.getKeyFormatPromise(keyFormats); } this.keyFormatPromise.then((keySystemFormat) => { const keySystem = keySystemFormatToKeySystemDomain(keySystemFormat); if (initDataType !== "sinf" || keySystem !== KeySystems.FAIRPLAY) { this.log(`Ignoring "${event.type}" event with init data type: "${initDataType}" for selected key-system ${keySystem}`); return; } let keyId; try { const json = bin2str(new Uint8Array(initData)); const tenc = parseSinf(base64Decode(JSON.parse(json).sinf)); if (!tenc) throw new Error(`'schm' box missing or not cbcs/cenc with schi > tenc`); keyId = new Uint8Array(tenc.subarray(8, 24)); } catch (error) { this.warn(`${logMessage} Failed to parse sinf: ${error}`); return; } const keyIdHex = arrayToHex(keyId); const { keyIdToKeySessionPromise, mediaKeySessions } = this; let keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex]; for (let i = 0; i < mediaKeySessions.length; i++) { const keyContext = mediaKeySessions[i]; const decryptdata = keyContext.decryptdata; if (!decryptdata.keyId) continue; const oldKeyIdHex = arrayToHex(decryptdata.keyId); if (arrayValuesMatch(keyId, decryptdata.keyId) || decryptdata.uri.replace(/-/g, "").indexOf(keyIdHex) !== -1) { keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex]; if (!keySessionContextPromise) continue; if (decryptdata.pssh) break; delete keyIdToKeySessionPromise[oldKeyIdHex]; decryptdata.pssh = new Uint8Array(initData); decryptdata.keyId = keyId; keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(() => { return this.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, "encrypted-event-key-match"); }); keySessionContextPromise.catch((error) => this.handleError(error)); break; } } if (!keySessionContextPromise) this.handleError(/* @__PURE__ */ new Error(`Key ID ${keyIdHex} not encountered in playlist. Key-system sessions ${mediaKeySessions.length}.`)); }).catch((error) => this.handleError(error)); }; this.onWaitingForKey = (event) => { this.log(`"${event.type}" event`); }; this.hls = hls; this.config = hls.config; this.registerListeners(); } destroy() { this.onDestroying(); this.onMediaDetached(); const config = this.config; config.requestMediaKeySystemAccessFunc = null; config.licenseXhrSetup = config.licenseResponseCallback = void 0; config.drmSystems = config.drmSystemOptions = {}; this.hls = this.config = this.keyIdToKeySessionPromise = null; this.onMediaEncrypted = this.onWaitingForKey = null; } registerListeners() { this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); this.hls.on(Events.MEDIA_DETACHED, this.onMediaDetached, this); this.hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); this.hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); this.hls.on(Events.DESTROYING, this.onDestroying, this); } unregisterListeners() { this.hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); this.hls.off(Events.MEDIA_DETACHED, this.onMediaDetached, this); this.hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); this.hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); this.hls.off(Events.DESTROYING, this.onDestroying, this); } getLicenseServerUrl(keySystem) { const { drmSystems, widevineLicenseUrl } = this.config; const keySystemConfiguration = drmSystems == null ? void 0 : drmSystems[keySystem]; if (keySystemConfiguration) return keySystemConfiguration.licenseUrl; if (keySystem === KeySystems.WIDEVINE && widevineLicenseUrl) return widevineLicenseUrl; } getLicenseServerUrlOrThrow(keySystem) { const url = this.getLicenseServerUrl(keySystem); if (url === void 0) throw new Error(`no license server URL configured for key-system "${keySystem}"`); return url; } getServerCertificateUrl(keySystem) { const { drmSystems } = this.config; const keySystemConfiguration = drmSystems == null ? void 0 : drmSystems[keySystem]; if (keySystemConfiguration) return keySystemConfiguration.serverCertificateUrl; else this.log(`No Server Certificate in config.drmSystems["${keySystem}"]`); } attemptKeySystemAccess(keySystemsToAttempt) { const levels = this.hls.levels; const uniqueCodec = (value, i, a) => !!value && a.indexOf(value) === i; const audioCodecs = levels.map((level) => level.audioCodec).filter(uniqueCodec); const videoCodecs = levels.map((level) => level.videoCodec).filter(uniqueCodec); if (audioCodecs.length + videoCodecs.length === 0) videoCodecs.push("avc1.42e01e"); return new Promise((resolve, reject) => { const attempt = (keySystems) => { const keySystem = keySystems.shift(); this.getMediaKeysPromise(keySystem, audioCodecs, videoCodecs).then((mediaKeys) => resolve({ keySystem, mediaKeys })).catch((error) => { if (keySystems.length) attempt(keySystems); else if (error instanceof EMEKeyError) reject(error); else reject(new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_ACCESS, error, fatal: true }, error.message)); }); }; attempt(keySystemsToAttempt); }); } requestMediaKeySystemAccess(keySystem, supportedConfigurations) { const { requestMediaKeySystemAccessFunc } = this.config; if (!(typeof requestMediaKeySystemAccessFunc === "function")) { let errMessage = `Configured requestMediaKeySystemAccess is not a function ${requestMediaKeySystemAccessFunc}`; if (requestMediaKeySystemAccess === null && self.location.protocol === "http:") errMessage = `navigator.requestMediaKeySystemAccess is not available over insecure protocol ${location.protocol}`; return Promise.reject(new Error(errMessage)); } return requestMediaKeySystemAccessFunc(keySystem, supportedConfigurations); } getMediaKeysPromise(keySystem, audioCodecs, videoCodecs) { var _keySystemAccessPromi; const mediaKeySystemConfigs = getSupportedMediaKeySystemConfigurations(keySystem, audioCodecs, videoCodecs, this.config.drmSystemOptions || {}); let keySystemAccessPromises = this.keySystemAccessPromises[keySystem]; let keySystemAccess = (_keySystemAccessPromi = keySystemAccessPromises) == null ? void 0 : _keySystemAccessPromi.keySystemAccess; if (!keySystemAccess) { this.log(`Requesting encrypted media "${keySystem}" key-system access with config: ${stringify(mediaKeySystemConfigs)}`); keySystemAccess = this.requestMediaKeySystemAccess(keySystem, mediaKeySystemConfigs); const keySystemAccessPromisesNew = keySystemAccessPromises = this.keySystemAccessPromises[keySystem] = { keySystemAccess }; keySystemAccess.catch((error) => { this.log(`Failed to obtain access to key-system "${keySystem}": ${error}`); }); return keySystemAccess.then((mediaKeySystemAccess) => { this.log(`Access for key-system "${mediaKeySystemAccess.keySystem}" obtained`); const certificateRequest = this.fetchServerCertificate(keySystem); this.log(`Create media-keys for "${keySystem}"`); const mediaKeys = keySystemAccessPromisesNew.mediaKeys = mediaKeySystemAccess.createMediaKeys().then((mediaKeys) => { this.log(`Media-keys created for "${keySystem}"`); keySystemAccessPromisesNew.hasMediaKeys = true; return certificateRequest.then((certificate) => { if (certificate) return this.setMediaKeysServerCertificate(mediaKeys, keySystem, certificate); return mediaKeys; }); }); mediaKeys.catch((error) => { this.error(`Failed to create media-keys for "${keySystem}"}: ${error}`); }); return mediaKeys; }); } return keySystemAccess.then(() => keySystemAccessPromises.mediaKeys); } createMediaKeySessionContext({ decryptdata, keySystem, mediaKeys }) { this.log(`Creating key-system session "${keySystem}" keyId: ${arrayToHex(decryptdata.keyId || [])} keyUri: ${decryptdata.uri}`); const mediaKeySessionContext = { decryptdata, keySystem, mediaKeys, mediaKeysSession: mediaKeys.createSession(), keyStatus: "status-pending" }; this.mediaKeySessions.push(mediaKeySessionContext); return mediaKeySessionContext; } renewKeySession(mediaKeySessionContext) { const decryptdata = mediaKeySessionContext.decryptdata; if (decryptdata.pssh) { const keySessionContext = this.createMediaKeySessionContext(mediaKeySessionContext); const keyId = getKeyIdString(decryptdata); const scheme = "cenc"; this.keyIdToKeySessionPromise[keyId] = this.generateRequestWithPreferredKeySession(keySessionContext, scheme, decryptdata.pssh.buffer, "expired"); } else this.warn(`Could not renew expired session. Missing pssh initData.`); this.removeSession(mediaKeySessionContext); } updateKeySession(mediaKeySessionContext, data) { const keySession = mediaKeySessionContext.mediaKeysSession; this.log(`Updating key-session "${keySession.sessionId}" for keyId ${arrayToHex(mediaKeySessionContext.decryptdata.keyId || [])} } (data length: ${data.byteLength})`); return keySession.update(data); } getSelectedKeySystemFormats() { return Object.keys(this.keySystemAccessPromises).map((keySystem) => ({ keySystem, hasMediaKeys: this.keySystemAccessPromises[keySystem].hasMediaKeys })).filter(({ hasMediaKeys }) => !!hasMediaKeys).map(({ keySystem }) => keySystemDomainToKeySystemFormat(keySystem)).filter((keySystem) => !!keySystem); } getKeySystemAccess(keySystemsToAttempt) { return this.getKeySystemSelectionPromise(keySystemsToAttempt).then(({ keySystem, mediaKeys }) => { return this.attemptSetMediaKeys(keySystem, mediaKeys); }); } selectKeySystem(keySystemsToAttempt) { return new Promise((resolve, reject) => { this.getKeySystemSelectionPromise(keySystemsToAttempt).then(({ keySystem }) => { const keySystemFormat = keySystemDomainToKeySystemFormat(keySystem); if (keySystemFormat) resolve(keySystemFormat); else reject(/* @__PURE__ */ new Error(`Unable to find format for key-system "${keySystem}"`)); }).catch(reject); }); } selectKeySystemFormat(frag) { const keyFormats = Object.keys(frag.levelkeys || {}); if (!this.keyFormatPromise) { this.log(`Selecting key-system from fragment (sn: ${frag.sn} ${frag.type}: ${frag.level}) key formats ${keyFormats.join(", ")}`); this.keyFormatPromise = this.getKeyFormatPromise(keyFormats); } return this.keyFormatPromise; } getKeyFormatPromise(keyFormats) { const keySystemsInConfig = getKeySystemsForConfig(this.config); const keySystemsToAttempt = keyFormats.map(keySystemFormatToKeySystemDomain).filter((value) => !!value && keySystemsInConfig.indexOf(value) !== -1); return this.selectKeySystem(keySystemsToAttempt); } getKeyStatus(decryptdata) { const { mediaKeySessions } = this; for (let i = 0; i < mediaKeySessions.length; i++) { const status = getKeyStatus(decryptdata, mediaKeySessions[i]); if (status) return status; } } loadKey(data) { const decryptdata = data.keyInfo.decryptdata; const keyId = getKeyIdString(decryptdata); const badStatus = this.bannedKeyIds[keyId]; if (badStatus || this.getKeyStatus(decryptdata) === "internal-error") { const error = getKeyStatusError(badStatus || "internal-error", decryptdata); this.handleError(error, data.frag); return Promise.reject(error); } const keyDetails = `(keyId: ${keyId} format: "${decryptdata.keyFormat}" method: ${decryptdata.method} uri: ${decryptdata.uri})`; this.log(`Starting session for key ${keyDetails}`); const keyContextPromise = this.keyIdToKeySessionPromise[keyId]; if (!keyContextPromise) { const keySessionContextPromise = this.getKeySystemForKeyPromise(decryptdata).then(({ keySystem, mediaKeys }) => { this.throwIfDestroyed(); this.log(`Handle encrypted media sn: ${data.frag.sn} ${data.frag.type}: ${data.frag.level} using key ${keyDetails}`); return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => { this.throwIfDestroyed(); return this.createMediaKeySessionContext({ keySystem, mediaKeys, decryptdata }); }); }).then((keySessionContext) => { const scheme = "cenc"; const initData = decryptdata.pssh ? decryptdata.pssh.buffer : null; return this.generateRequestWithPreferredKeySession(keySessionContext, scheme, initData, "playlist-key"); }); keySessionContextPromise.catch((error) => this.handleError(error, data.frag)); this.keyIdToKeySessionPromise[keyId] = keySessionContextPromise; return keySessionContextPromise; } keyContextPromise.catch((error) => { if (error instanceof EMEKeyError) { const errorData = _objectSpread2({}, error.data); if (this.getKeyStatus(decryptdata) === "internal-error") errorData.decryptdata = decryptdata; const clonedError = new EMEKeyError(errorData, error.message); this.handleError(clonedError, data.frag); } }); return keyContextPromise; } throwIfDestroyed(message = "Invalid state") { if (!this.hls) throw new Error("invalid state"); } handleError(error, frag) { if (!this.hls) return; if (error instanceof EMEKeyError) { if (frag) error.data.frag = frag; const levelKey = error.data.decryptdata; this.error(`${error.message}${levelKey ? ` (${arrayToHex(levelKey.keyId || [])})` : ""}`); this.hls.trigger(Events.ERROR, error.data); } else { this.error(error.message); this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_KEYS, error, fatal: true }); } } getKeySystemForKeyPromise(decryptdata) { const keyId = getKeyIdString(decryptdata); const mediaKeySessionContext = this.keyIdToKeySessionPromise[keyId]; if (!mediaKeySessionContext) { const keySystem = keySystemFormatToKeySystemDomain(decryptdata.keyFormat); const keySystemsToAttempt = keySystem ? [keySystem] : getKeySystemsForConfig(this.config); return this.attemptKeySystemAccess(keySystemsToAttempt); } return mediaKeySessionContext; } getKeySystemSelectionPromise(keySystemsToAttempt) { if (!keySystemsToAttempt.length) keySystemsToAttempt = getKeySystemsForConfig(this.config); if (keySystemsToAttempt.length === 0) throw new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_CONFIGURED_LICENSE, fatal: true }, `Missing key-system license configuration options ${stringify({ drmSystems: this.config.drmSystems })}`); return this.attemptKeySystemAccess(keySystemsToAttempt); } attemptSetMediaKeys(keySystem, mediaKeys) { this.mediaResolved = void 0; if (this.mediaKeys === mediaKeys) return Promise.resolve(); const queue = this.setMediaKeysQueue.slice(); this.log(`Setting media-keys for "${keySystem}"`); const setMediaKeysPromise = Promise.all(queue).then(() => { if (!this.media) return new Promise((resolve, reject) => { this.mediaResolved = () => { this.mediaResolved = void 0; if (!this.media) return reject(/* @__PURE__ */ new Error("Attempted to set mediaKeys without media element attached")); this.mediaKeys = mediaKeys; this.media.setMediaKeys(mediaKeys).then(resolve).catch(reject); }; }); return this.media.setMediaKeys(mediaKeys); }); this.mediaKeys = mediaKeys; this.setMediaKeysQueue.push(setMediaKeysPromise); return setMediaKeysPromise.then(() => { this.log(`Media-keys set for "${keySystem}"`); queue.push(setMediaKeysPromise); this.setMediaKeysQueue = this.setMediaKeysQueue.filter((p) => queue.indexOf(p) === -1); }); } generateRequestWithPreferredKeySession(context, initDataType, initData, reason) { var _this$config$drmSyste; const generateRequestFilter = (_this$config$drmSyste = this.config.drmSystems) == null || (_this$config$drmSyste = _this$config$drmSyste[context.keySystem]) == null ? void 0 : _this$config$drmSyste.generateRequest; if (generateRequestFilter) try { const mappedInitData = generateRequestFilter.call(this.hls, initDataType, initData, context); if (!mappedInitData) throw new Error("Invalid response from configured generateRequest filter"); initDataType = mappedInitData.initDataType; initData = mappedInitData.initData ? mappedInitData.initData : null; context.decryptdata.pssh = initData ? new Uint8Array(initData) : null; } catch (error) { this.warn(error.message); if (this.hls && this.hls.config.debug) throw error; } if (initData === null) { this.log(`Skipping key-session request for "${reason}" (no initData)`); return Promise.resolve(context); } const keyId = getKeyIdString(context.decryptdata); const keyUri = context.decryptdata.uri; this.log(`Generating key-session request for "${reason}" keyId: ${keyId} URI: ${keyUri} (init data type: ${initDataType} length: ${initData.byteLength})`); const licenseStatus = new EventEmitter(); const onmessage = context._onmessage = (event) => { const keySession = context.mediaKeysSession; if (!keySession) { licenseStatus.emit("error", /* @__PURE__ */ new Error("invalid state")); return; } const { messageType, message } = event; this.log(`"${messageType}" message event for session "${keySession.sessionId}" message size: ${message.byteLength}`); if (messageType === "license-request" || messageType === "license-renewal") this.renewLicense(context, message).catch((error) => { if (licenseStatus.eventNames().length) licenseStatus.emit("error", error); else this.handleError(error); }); else if (messageType === "license-release") { if (context.keySystem === KeySystems.FAIRPLAY) this.updateKeySession(context, strToUtf8array("acknowledged")).then(() => this.removeSession(context)).catch((error) => this.handleError(error)); } else this.warn(`unhandled media key message type "${messageType}"`); }; const handleKeyStatus = (keyStatus, context) => { context.keyStatus = keyStatus; let keyError; if (keyStatus.startsWith("usable")) licenseStatus.emit("resolved"); else if (keyStatus === "internal-error" || keyStatus === "output-restricted" || keyStatus === "output-downscaled") keyError = getKeyStatusError(keyStatus, context.decryptdata); else if (keyStatus === "expired") keyError = /* @__PURE__ */ new Error(`key expired (keyId: ${keyId})`); else if (keyStatus === "released") keyError = /* @__PURE__ */ new Error(`key released`); else if (keyStatus === "status-pending"); else this.warn(`unhandled key status change "${keyStatus}" (keyId: ${keyId})`); if (keyError) if (licenseStatus.eventNames().length) licenseStatus.emit("error", keyError); else this.handleError(keyError); }; const onkeystatuseschange = context._onkeystatuseschange = (event) => { if (!context.mediaKeysSession) { licenseStatus.emit("error", /* @__PURE__ */ new Error("invalid state")); return; } const keyStatuses = this.getKeyStatuses(context); if (!Object.keys(keyStatuses).some((id) => keyStatuses[id] !== "status-pending")) return; if (keyStatuses[keyId] === "expired") { this.log(`Expired key ${stringify(keyStatuses)} in key-session "${context.mediaKeysSession.sessionId}"`); this.renewKeySession(context); return; } let keyStatus = keyStatuses[keyId]; if (keyStatus) handleKeyStatus(keyStatus, context); else { var _context$keyStatusTim; const timeout = 1e3; context.keyStatusTimeouts || (context.keyStatusTimeouts = {}); (_context$keyStatusTim = context.keyStatusTimeouts)[keyId] || (_context$keyStatusTim[keyId] = self.setTimeout(() => { if (!context.mediaKeysSession || !this.mediaKeys) return; const sessionKeyStatus = this.getKeyStatus(context.decryptdata); if (sessionKeyStatus && sessionKeyStatus !== "status-pending") { this.log(`No status for keyId ${keyId} in key-session "${context.mediaKeysSession.sessionId}". Using session key-status ${sessionKeyStatus} from other session.`); return handleKeyStatus(sessionKeyStatus, context); } this.log(`key status for ${keyId} in key-session "${context.mediaKeysSession.sessionId}" timed out after ${timeout}ms`); keyStatus = "internal-error"; handleKeyStatus(keyStatus, context); }, timeout)); this.log(`No status for keyId ${keyId} (${stringify(keyStatuses)}).`); } }; addEventListener(context.mediaKeysSession, "message", onmessage); addEventListener(context.mediaKeysSession, "keystatuseschange", onkeystatuseschange); const keyUsablePromise = new Promise((resolve, reject) => { licenseStatus.on("error", reject); licenseStatus.on("resolved", resolve); }); return context.mediaKeysSession.generateRequest(initDataType, initData).then(() => { this.log(`Request generated for key-session "${context.mediaKeysSession.sessionId}" keyId: ${keyId} URI: ${keyUri}`); }).catch((error) => { throw new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_SESSION, error, decryptdata: context.decryptdata, fatal: false }, `Error generating key-session request: ${error}`); }).then(() => keyUsablePromise).catch((error) => { licenseStatus.removeAllListeners(); return this.removeSession(context).then(() => { throw error; }); }).then(() => { licenseStatus.removeAllListeners(); return context; }); } getKeyStatuses(mediaKeySessionContext) { const keyStatuses = {}; mediaKeySessionContext.mediaKeysSession.keyStatuses.forEach((status, keyId) => { if (typeof keyId === "string" && typeof status === "object") { const temp = keyId; keyId = status; status = temp; } const keyIdArray = "buffer" in keyId ? new Uint8Array(keyId.buffer, keyId.byteOffset, keyId.byteLength) : new Uint8Array(keyId); if (mediaKeySessionContext.keySystem === KeySystems.PLAYREADY && keyIdArray.length === 16) { const originKeyIdWithStatusChange = arrayToHex(keyIdArray); keyStatuses[originKeyIdWithStatusChange] = status; changeEndianness(keyIdArray); } const keyIdWithStatusChange = arrayToHex(keyIdArray); if (status === "internal-error") this.bannedKeyIds[keyIdWithStatusChange] = status; this.log(`key status change "${status}" for keyStatuses keyId: ${keyIdWithStatusChange} key-session "${mediaKeySessionContext.mediaKeysSession.sessionId}"`); keyStatuses[keyIdWithStatusChange] = status; }); return keyStatuses; } fetchServerCertificate(keySystem) { const config = this.config; const Loader = config.loader; const certLoader = new Loader(config); const url = this.getServerCertificateUrl(keySystem); if (!url) return Promise.resolve(); this.log(`Fetching server certificate for "${keySystem}"`); return new Promise((resolve, reject) => { const loaderContext = { responseType: "arraybuffer", url }; const loadPolicy = config.certLoadPolicy.default; const loaderConfig = { loadPolicy, timeout: loadPolicy.maxLoadTimeMs, maxRetry: 0, retryDelay: 0, maxRetryDelay: 0 }; certLoader.load(loaderContext, loaderConfig, { onSuccess: (response, stats, context, networkDetails) => { resolve(response.data); }, onError: (response, contex, networkDetails, stats) => { reject(new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED, fatal: true, networkDetails, response: _objectSpread2({ url: loaderContext.url, data: void 0 }, response) }, `"${keySystem}" certificate request failed (${url}). Status: ${response.code} (${response.text})`)); }, onTimeout: (stats, context, networkDetails) => { reject(new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED, fatal: true, networkDetails, response: { url: loaderContext.url, data: void 0 } }, `"${keySystem}" certificate request timed out (${url})`)); }, onAbort: (stats, context, networkDetails) => { reject(/* @__PURE__ */ new Error("aborted")); } }); }); } setMediaKeysServerCertificate(mediaKeys, keySystem, cert) { return new Promise((resolve, reject) => { mediaKeys.setServerCertificate(cert).then((success) => { this.log(`setServerCertificate ${success ? "success" : "not supported by CDM"} (${cert.byteLength}) on "${keySystem}"`); resolve(mediaKeys); }).catch((error) => { reject(new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED, error, fatal: true }, error.message)); }); }); } renewLicense(context, keyMessage) { return this.requestLicense(context, new Uint8Array(keyMessage)).then((data) => { return this.updateKeySession(context, new Uint8Array(data)).catch((error) => { throw new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_SESSION_UPDATE_FAILED, decryptdata: context.decryptdata, error, fatal: false }, error.message); }); }); } unpackPlayReadyKeyMessage(xhr, licenseChallenge) { const xmlString = String.fromCharCode.apply(null, new Uint16Array(licenseChallenge.buffer)); if (!xmlString.includes("PlayReadyKeyMessage")) { xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); return licenseChallenge; } const keyMessageXml = new DOMParser().parseFromString(xmlString, "application/xml"); const headers = keyMessageXml.querySelectorAll("HttpHeader"); if (headers.length > 0) { let header; for (let i = 0, len = headers.length; i < len; i++) { var _header$querySelector, _header$querySelector2; header = headers[i]; const name = (_header$querySelector = header.querySelector("name")) == null ? void 0 : _header$querySelector.textContent; const value = (_header$querySelector2 = header.querySelector("value")) == null ? void 0 : _header$querySelector2.textContent; if (name && value) xhr.setRequestHeader(name, value); } } const challengeElement = keyMessageXml.querySelector("Challenge"); const challengeText = challengeElement == null ? void 0 : challengeElement.textContent; if (!challengeText) throw new Error(`Cannot find in key message`); return strToUtf8array(atob(challengeText)); } setupLicenseXHR(xhr, url, keysListItem, licenseChallenge) { const licenseXhrSetup = this.config.licenseXhrSetup; if (!licenseXhrSetup) { xhr.open("POST", url, true); return Promise.resolve({ xhr, licenseChallenge }); } return Promise.resolve().then(() => { if (!keysListItem.decryptdata) throw new Error("Key removed"); return licenseXhrSetup.call(this.hls, xhr, url, keysListItem, licenseChallenge); }).catch((error) => { if (!keysListItem.decryptdata) throw error; xhr.open("POST", url, true); return licenseXhrSetup.call(this.hls, xhr, url, keysListItem, licenseChallenge); }).then((licenseXhrSetupResult) => { if (!xhr.readyState) xhr.open("POST", url, true); return { xhr, licenseChallenge: licenseXhrSetupResult ? licenseXhrSetupResult : licenseChallenge }; }); } requestLicense(keySessionContext, licenseChallenge) { const keyLoadPolicy = this.config.keyLoadPolicy.default; return new Promise((resolve, reject) => { const url = this.getLicenseServerUrlOrThrow(keySessionContext.keySystem); this.log(`Sending license request to URL: ${url}`); const xhr = new XMLHttpRequest(); xhr.responseType = "arraybuffer"; xhr.onreadystatechange = () => { if (!this.hls || !keySessionContext.mediaKeysSession) return reject(/* @__PURE__ */ new Error("invalid state")); if (xhr.readyState === 4) if (xhr.status === 200) { this._requestLicenseFailureCount = 0; let data = xhr.response; this.log(`License received ${data instanceof ArrayBuffer ? data.byteLength : data}`); const licenseResponseCallback = this.config.licenseResponseCallback; if (licenseResponseCallback) try { data = licenseResponseCallback.call(this.hls, xhr, url, keySessionContext); } catch (error) { this.error(error); } resolve(data); } else { const retryConfig = keyLoadPolicy.errorRetry; const maxNumRetry = retryConfig ? retryConfig.maxNumRetry : 0; this._requestLicenseFailureCount++; if (this._requestLicenseFailureCount > maxNumRetry || xhr.status >= 400 && xhr.status < 500) reject(new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED, decryptdata: keySessionContext.decryptdata, fatal: true, networkDetails: xhr, response: { url, data: void 0, code: xhr.status, text: xhr.statusText } }, `License Request XHR failed (${url}). Status: ${xhr.status} (${xhr.statusText})`)); else { const attemptsLeft = maxNumRetry - this._requestLicenseFailureCount + 1; this.warn(`Retrying license request, ${attemptsLeft} attempts left`); this.requestLicense(keySessionContext, licenseChallenge).then(resolve, reject); } } }; if (keySessionContext.licenseXhr && keySessionContext.licenseXhr.readyState !== XMLHttpRequest.DONE) keySessionContext.licenseXhr.abort(); keySessionContext.licenseXhr = xhr; this.setupLicenseXHR(xhr, url, keySessionContext, licenseChallenge).then(({ xhr, licenseChallenge }) => { if (keySessionContext.keySystem == KeySystems.PLAYREADY) licenseChallenge = this.unpackPlayReadyKeyMessage(xhr, licenseChallenge); xhr.send(licenseChallenge); }).catch(reject); }); } onDestroying() { this.unregisterListeners(); this._clear(); } onMediaAttached(event, data) { if (!this.config.emeEnabled) return; const media = data.media; this.media = media; addEventListener(media, "encrypted", this.onMediaEncrypted); addEventListener(media, "waitingforkey", this.onWaitingForKey); const mediaResolved = this.mediaResolved; if (mediaResolved) mediaResolved(); else this.mediaKeys = media.mediaKeys; } onMediaDetached() { const media = this.media; if (media) { removeEventListener(media, "encrypted", this.onMediaEncrypted); removeEventListener(media, "waitingforkey", this.onWaitingForKey); this.media = null; this.mediaKeys = null; } } _clear() { var _media$setMediaKeys; this._requestLicenseFailureCount = 0; this.keyIdToKeySessionPromise = {}; this.bannedKeyIds = {}; const mediaResolved = this.mediaResolved; if (mediaResolved) mediaResolved(); if (!this.mediaKeys && !this.mediaKeySessions.length) return; const media = this.media; const mediaKeysList = this.mediaKeySessions.slice(); this.mediaKeySessions = []; this.mediaKeys = null; LevelKey.clearKeyUriToKeyIdMap(); const keySessionCount = mediaKeysList.length; EMEController.CDMCleanupPromise = Promise.all(mediaKeysList.map((mediaKeySessionContext) => this.removeSession(mediaKeySessionContext)).concat((media == null || (_media$setMediaKeys = media.setMediaKeys(null)) == null ? void 0 : _media$setMediaKeys.catch((error) => { this.log(`Could not clear media keys: ${error}`); if (!this.hls) return; this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR, fatal: false, error: /* @__PURE__ */ new Error(`Could not clear media keys: ${error}`) }); })) || Promise.resolve())).catch((error) => { this.log(`Could not close sessions and clear media keys: ${error}`); if (!this.hls) return; this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR, fatal: false, error: /* @__PURE__ */ new Error(`Could not close sessions and clear media keys: ${error}`) }); }).then(() => { if (keySessionCount) this.log("finished closing key sessions and clearing media keys"); }); } onManifestLoading() { this._clear(); } onManifestLoaded(event, { sessionKeys }) { if (!sessionKeys || !this.config.emeEnabled) return; if (!this.keyFormatPromise) { const keyFormats = sessionKeys.reduce((formats, sessionKey) => { if (formats.indexOf(sessionKey.keyFormat) === -1) formats.push(sessionKey.keyFormat); return formats; }, []); this.log(`Selecting key-system from session-keys ${keyFormats.join(", ")}`); this.keyFormatPromise = this.getKeyFormatPromise(keyFormats); } } removeSession(mediaKeySessionContext) { const { mediaKeysSession, licenseXhr, decryptdata } = mediaKeySessionContext; if (mediaKeysSession) { this.log(`Remove licenses and keys and close session "${mediaKeysSession.sessionId}" keyId: ${arrayToHex((decryptdata == null ? void 0 : decryptdata.keyId) || [])}`); if (mediaKeySessionContext._onmessage) { mediaKeysSession.removeEventListener("message", mediaKeySessionContext._onmessage); mediaKeySessionContext._onmessage = void 0; } if (mediaKeySessionContext._onkeystatuseschange) { mediaKeysSession.removeEventListener("keystatuseschange", mediaKeySessionContext._onkeystatuseschange); mediaKeySessionContext._onkeystatuseschange = void 0; } if (licenseXhr && licenseXhr.readyState !== XMLHttpRequest.DONE) licenseXhr.abort(); mediaKeySessionContext.mediaKeysSession = mediaKeySessionContext.decryptdata = mediaKeySessionContext.licenseXhr = void 0; const index = this.mediaKeySessions.indexOf(mediaKeySessionContext); if (index > -1) this.mediaKeySessions.splice(index, 1); const { keyStatusTimeouts } = mediaKeySessionContext; if (keyStatusTimeouts) Object.keys(keyStatusTimeouts).forEach((keyId) => self.clearTimeout(keyStatusTimeouts[keyId])); const { drmSystemOptions } = this.config; return (isPersistentSessionType(drmSystemOptions) ? new Promise((resolve, reject) => { self.setTimeout(() => reject(/* @__PURE__ */ new Error(`MediaKeySession.remove() timeout`)), 8e3); mediaKeysSession.remove().then(resolve).catch(reject); }) : Promise.resolve()).catch((error) => { this.log(`Could not remove session: ${error}`); if (!this.hls) return; this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR, fatal: false, error: /* @__PURE__ */ new Error(`Could not remove session: ${error}`) }); }).then(() => { return mediaKeysSession.close(); }).catch((error) => { this.log(`Could not close session: ${error}`); if (!this.hls) return; this.hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR, fatal: false, error: /* @__PURE__ */ new Error(`Could not close session: ${error}`) }); }); } return Promise.resolve(); } }; EMEController.CDMCleanupPromise = void 0; function getKeyIdString(decryptdata) { if (!decryptdata) throw new Error("Could not read keyId of undefined decryptdata"); if (decryptdata.keyId === null) throw new Error("keyId is null"); return arrayToHex(decryptdata.keyId); } function getKeyStatus(decryptdata, keyContext) { if (decryptdata.keyId && keyContext.mediaKeysSession.keyStatuses.has(decryptdata.keyId)) return keyContext.mediaKeysSession.keyStatuses.get(decryptdata.keyId); if (decryptdata.matches(keyContext.decryptdata)) return keyContext.keyStatus; } var EMEKeyError = class extends Error { constructor(data, message) { super(message); this.data = void 0; data.error || (data.error = new Error(message)); this.data = data; data.err = data.error; } }; function getKeyStatusError(keyStatus, decryptdata) { const outputRestricted = keyStatus === "output-restricted"; const details = outputRestricted ? ErrorDetails.KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED : ErrorDetails.KEY_SYSTEM_STATUS_INTERNAL_ERROR; return new EMEKeyError({ type: ErrorTypes.KEY_SYSTEM_ERROR, details, fatal: false, decryptdata }, outputRestricted ? "HDCP level output restricted" : `key status changed to "${keyStatus}"`); } var FPSController = class { constructor(hls) { this.hls = void 0; this.isVideoPlaybackQualityAvailable = false; this.timer = void 0; this.media = null; this.lastTime = void 0; this.lastDroppedFrames = 0; this.lastDecodedFrames = 0; this.streamController = void 0; this.hls = hls; this.registerListeners(); } setStreamController(streamController) { this.streamController = streamController; } registerListeners() { this.hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); this.hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); } unregisterListeners() { this.hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); this.hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); } destroy() { if (this.timer) clearInterval(this.timer); this.unregisterListeners(); this.isVideoPlaybackQualityAvailable = false; this.media = null; } onMediaAttaching(event, data) { const config = this.hls.config; if (config.capLevelOnFPSDrop) { const media = data.media instanceof self.HTMLVideoElement ? data.media : null; this.media = media; if (media && typeof media.getVideoPlaybackQuality === "function") this.isVideoPlaybackQualityAvailable = true; self.clearInterval(this.timer); this.timer = self.setInterval(this.checkFPSInterval.bind(this), config.fpsDroppedMonitoringPeriod); } } onMediaDetaching() { this.media = null; } checkFPS(video, decodedFrames, droppedFrames) { const currentTime = performance.now(); if (decodedFrames) { if (this.lastTime) { const currentPeriod = currentTime - this.lastTime; const currentDropped = droppedFrames - this.lastDroppedFrames; const currentDecoded = decodedFrames - this.lastDecodedFrames; const droppedFPS = 1e3 * currentDropped / currentPeriod; const hls = this.hls; hls.trigger(Events.FPS_DROP, { currentDropped, currentDecoded, totalDroppedFrames: droppedFrames }); if (droppedFPS > 0) { if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) { let currentLevel = hls.currentLevel; hls.logger.warn("drop FPS ratio greater than max allowed value for currentLevel: " + currentLevel); if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) { currentLevel = currentLevel - 1; hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, { level: currentLevel, droppedLevel: hls.currentLevel }); hls.autoLevelCapping = currentLevel; this.streamController.nextLevelSwitch(); } } } } this.lastTime = currentTime; this.lastDroppedFrames = droppedFrames; this.lastDecodedFrames = decodedFrames; } } checkFPSInterval() { const video = this.media; if (video) if (this.isVideoPlaybackQualityAvailable) { const videoPlaybackQuality = video.getVideoPlaybackQuality(); this.checkFPS(video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames); } else this.checkFPS(video, video.webkitDecodedFrameCount, video.webkitDroppedFrameCount); } }; function sendAddTrackEvent(track, videoEl) { let event; try { event = new Event("addtrack"); } catch (err) { event = document.createEvent("Event"); event.initEvent("addtrack", false, false); } event.track = track; videoEl.dispatchEvent(event); } function addCueToTrack(track, cue) { const mode = track.mode; if (mode === "disabled") track.mode = "hidden"; if (track.cues && !track.cues.getCueById(cue.id)) try { track.addCue(cue); if (!track.cues.getCueById(cue.id)) throw new Error(`addCue is failed for: ${cue}`); } catch (err) { logger.debug(`[texttrack-utils]: ${err}`); try { const textTrackCue = new self.TextTrackCue(cue.startTime, cue.endTime, cue.text); textTrackCue.id = cue.id; track.addCue(textTrackCue); } catch (err2) { logger.debug(`[texttrack-utils]: Legacy TextTrackCue fallback failed: ${err2}`); } } if (mode === "disabled") track.mode = mode; } function clearCurrentCues(track, enterHandler) { const mode = track.mode; if (mode === "disabled") track.mode = "hidden"; if (track.cues) for (let i = track.cues.length; i--;) { if (enterHandler) track.cues[i].removeEventListener("enter", enterHandler); track.removeCue(track.cues[i]); } if (mode === "disabled") track.mode = mode; } function removeCuesInRange(track, start, end, predicate) { const mode = track.mode; if (mode === "disabled") track.mode = "hidden"; if (track.cues && track.cues.length > 0) { const cues = getCuesInRange(track.cues, start, end); for (let i = 0; i < cues.length; i++) if (!predicate || predicate(cues[i])) track.removeCue(cues[i]); } if (mode === "disabled") track.mode = mode; } function getFirstCueIndexFromTime(cues, time) { if (time <= cues[0].startTime) return 0; const len = cues.length - 1; if (time > cues[len].endTime) return -1; let left = 0; let right = len; let mid; while (left <= right) { mid = Math.floor((right + left) / 2); if (time < cues[mid].startTime) right = mid - 1; else if (time > cues[mid].startTime && left < len) left = mid + 1; else return mid; } return cues[left].startTime - time < time - cues[right].startTime ? left : right; } function getCuesInRange(cues, start, end) { const cuesFound = []; const firstCueInRange = getFirstCueIndexFromTime(cues, start); if (firstCueInRange > -1) for (let i = firstCueInRange, len = cues.length; i < len; i++) { const cue = cues[i]; if (cue.startTime >= start && cue.endTime <= end) cuesFound.push(cue); else if (cue.startTime > end) return cuesFound; } return cuesFound; } function filterSubtitleTracks(textTrackList) { const tracks = []; for (let i = 0; i < textTrackList.length; i++) { const track = textTrackList[i]; if ((track.kind === "subtitles" || track.kind === "captions") && track.label) tracks.push(textTrackList[i]); } return tracks; } var SubtitleTrackController = class extends BasePlaylistController { constructor(hls) { super(hls, "subtitle-track-controller"); this.media = null; this.tracks = []; this.groupIds = null; this.tracksInGroup = []; this.trackId = -1; this.currentTrack = null; this.selectDefaultTrack = true; this.queuedDefaultTrack = -1; this.useTextTrackPolling = false; this.subtitlePollingInterval = -1; this._subtitleDisplay = true; this.asyncPollTrackChange = () => this.pollTrackChange(0); this.onTextTracksChanged = () => { if (!this.useTextTrackPolling) self.clearInterval(this.subtitlePollingInterval); if (!this.media || !this.hls.config.renderTextTracksNatively) return; let textTrack = null; const tracks = filterSubtitleTracks(this.media.textTracks); for (let i = 0; i < tracks.length; i++) if (tracks[i].mode === "hidden") textTrack = tracks[i]; else if (tracks[i].mode === "showing") { textTrack = tracks[i]; break; } const trackId = this.findTrackForTextTrack(textTrack); if (this.subtitleTrack !== trackId) this.setSubtitleTrack(trackId); }; this.registerListeners(); } destroy() { this.unregisterListeners(); this.tracks.length = 0; this.tracksInGroup.length = 0; this.currentTrack = null; this.onTextTracksChanged = this.asyncPollTrackChange = null; super.destroy(); } get subtitleDisplay() { return this._subtitleDisplay; } set subtitleDisplay(value) { this._subtitleDisplay = value; if (this.trackId > -1) this.toggleTrackModes(); } registerListeners() { const { hls } = this; hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this); hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); hls.on(Events.ERROR, this.onError, this); } unregisterListeners() { const { hls } = this; hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this); hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this); hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); hls.off(Events.ERROR, this.onError, this); } onMediaAttached(event, data) { this.media = data.media; if (!this.media) return; if (this.queuedDefaultTrack > -1) { this.subtitleTrack = this.queuedDefaultTrack; this.queuedDefaultTrack = -1; } this.useTextTrackPolling = !(this.media.textTracks && "onchange" in this.media.textTracks); if (this.useTextTrackPolling) this.pollTrackChange(500); else this.media.textTracks.addEventListener("change", this.asyncPollTrackChange); } pollTrackChange(timeout) { self.clearInterval(this.subtitlePollingInterval); this.subtitlePollingInterval = self.setInterval(this.onTextTracksChanged, timeout); } onMediaDetaching(event, data) { const media = this.media; if (!media) return; const transferringMedia = !!data.transferMedia; self.clearInterval(this.subtitlePollingInterval); if (!this.useTextTrackPolling) media.textTracks.removeEventListener("change", this.asyncPollTrackChange); if (this.trackId > -1) this.queuedDefaultTrack = this.trackId; this.subtitleTrack = -1; this.media = null; if (transferringMedia) return; filterSubtitleTracks(media.textTracks).forEach((track) => { clearCurrentCues(track); }); } onManifestLoading() { this.tracks = []; this.groupIds = null; this.tracksInGroup = []; this.trackId = -1; this.currentTrack = null; this.selectDefaultTrack = true; } onManifestParsed(event, data) { this.tracks = data.subtitleTracks; } onSubtitleTrackLoaded(event, data) { const { id, groupId, details } = data; const trackInActiveGroup = this.tracksInGroup[id]; if (!trackInActiveGroup || trackInActiveGroup.groupId !== groupId) { this.warn(`Subtitle track with id:${id} and group:${groupId} not found in active group ${trackInActiveGroup == null ? void 0 : trackInActiveGroup.groupId}`); return; } const curDetails = trackInActiveGroup.details; trackInActiveGroup.details = data.details; this.log(`Subtitle track ${id} "${trackInActiveGroup.name}" lang:${trackInActiveGroup.lang} group:${groupId} loaded [${details.startSN}-${details.endSN}]`); if (id === this.trackId) this.playlistLoaded(id, data, curDetails); } onLevelLoading(event, data) { this.switchLevel(data.level); } onLevelSwitching(event, data) { this.switchLevel(data.level); } switchLevel(levelIndex) { const levelInfo = this.hls.levels[levelIndex]; if (!levelInfo) return; const subtitleGroups = levelInfo.subtitleGroups || null; const currentGroups = this.groupIds; let currentTrack = this.currentTrack; if (!subtitleGroups || (currentGroups == null ? void 0 : currentGroups.length) !== (subtitleGroups == null ? void 0 : subtitleGroups.length) || subtitleGroups != null && subtitleGroups.some((groupId) => (currentGroups == null ? void 0 : currentGroups.indexOf(groupId)) === -1)) { this.groupIds = subtitleGroups; this.trackId = -1; this.currentTrack = null; const subtitleTracks = this.tracks.filter((track) => !subtitleGroups || subtitleGroups.indexOf(track.groupId) !== -1); if (subtitleTracks.length) { if (this.selectDefaultTrack && !subtitleTracks.some((track) => track.default)) this.selectDefaultTrack = false; subtitleTracks.forEach((track, i) => { track.id = i; }); } else if (!currentTrack && !this.tracksInGroup.length) return; this.tracksInGroup = subtitleTracks; const subtitlePreference = this.hls.config.subtitlePreference; if (!currentTrack && subtitlePreference) { this.selectDefaultTrack = false; const groupIndex = findMatchingOption(subtitlePreference, subtitleTracks); if (groupIndex > -1) currentTrack = subtitleTracks[groupIndex]; else { const allIndex = findMatchingOption(subtitlePreference, this.tracks); currentTrack = this.tracks[allIndex]; } } let trackId = this.findTrackId(currentTrack); if (trackId === -1 && currentTrack) trackId = this.findTrackId(null); const subtitleTracksUpdated = { subtitleTracks }; this.log(`Updating subtitle tracks, ${subtitleTracks.length} track(s) found in "${subtitleGroups == null ? void 0 : subtitleGroups.join(",")}" group-id`); this.hls.trigger(Events.SUBTITLE_TRACKS_UPDATED, subtitleTracksUpdated); if (trackId !== -1 && this.trackId === -1) this.setSubtitleTrack(trackId); } } findTrackId(currentTrack) { const tracks = this.tracksInGroup; const selectDefault = this.selectDefaultTrack; for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; if (selectDefault && !track.default || !selectDefault && !currentTrack) continue; if (!currentTrack || matchesOption(track, currentTrack)) return i; } if (currentTrack) { for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; if (mediaAttributesIdentical(currentTrack.attrs, track.attrs, [ "LANGUAGE", "ASSOC-LANGUAGE", "CHARACTERISTICS" ])) return i; } for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; if (mediaAttributesIdentical(currentTrack.attrs, track.attrs, ["LANGUAGE"])) return i; } } return -1; } findTrackForTextTrack(textTrack) { if (textTrack) { const tracks = this.tracksInGroup; for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; if (subtitleTrackMatchesTextTrack(track, textTrack)) return i; } } return -1; } onError(event, data) { if (data.fatal || !data.context) return; if (data.context.type === PlaylistContextType.SUBTITLE_TRACK && data.context.id === this.trackId && (!this.groupIds || this.groupIds.indexOf(data.context.groupId) !== -1)) this.checkRetry(data); } get allSubtitleTracks() { return this.tracks; } /** get alternate subtitle tracks list from playlist **/ get subtitleTracks() { return this.tracksInGroup; } /** get/set index of the selected subtitle track (based on index in subtitle track lists) **/ get subtitleTrack() { return this.trackId; } set subtitleTrack(newId) { this.selectDefaultTrack = false; this.setSubtitleTrack(newId); } setSubtitleOption(subtitleOption) { this.hls.config.subtitlePreference = subtitleOption; if (subtitleOption) { if (subtitleOption.id === -1) { this.setSubtitleTrack(-1); return null; } const allSubtitleTracks = this.allSubtitleTracks; this.selectDefaultTrack = false; if (allSubtitleTracks.length) { const currentTrack = this.currentTrack; if (currentTrack && matchesOption(subtitleOption, currentTrack)) return currentTrack; const groupIndex = findMatchingOption(subtitleOption, this.tracksInGroup); if (groupIndex > -1) { const track = this.tracksInGroup[groupIndex]; this.setSubtitleTrack(groupIndex); return track; } else if (currentTrack) return null; else { const allIndex = findMatchingOption(subtitleOption, allSubtitleTracks); if (allIndex > -1) return allSubtitleTracks[allIndex]; } } } return null; } loadPlaylist(hlsUrlParameters) { super.loadPlaylist(); if (this.shouldLoadPlaylist(this.currentTrack)) this.scheduleLoading(this.currentTrack, hlsUrlParameters); } loadingPlaylist(currentTrack, hlsUrlParameters) { super.loadingPlaylist(currentTrack, hlsUrlParameters); const id = currentTrack.id; const groupId = currentTrack.groupId; const url = this.getUrlWithDirectives(currentTrack.url, hlsUrlParameters); const details = currentTrack.details; const age = details == null ? void 0 : details.age; this.log(`Loading subtitle ${id} "${currentTrack.name}" lang:${currentTrack.lang} group:${groupId}${(hlsUrlParameters == null ? void 0 : hlsUrlParameters.msn) !== void 0 ? " at sn " + hlsUrlParameters.msn + " part " + hlsUrlParameters.part : ""}${age && details.live ? " age " + age.toFixed(1) + (details.type ? " " + details.type || "" : "") : ""} ${url}`); this.hls.trigger(Events.SUBTITLE_TRACK_LOADING, { url, id, groupId, deliveryDirectives: hlsUrlParameters || null, track: currentTrack }); } /** * Disables the old subtitleTrack and sets current mode on the next subtitleTrack. * This operates on the DOM textTracks. * A value of -1 will disable all subtitle tracks. */ toggleTrackModes() { const { media } = this; if (!media) return; const textTracks = filterSubtitleTracks(media.textTracks); const currentTrack = this.currentTrack; let nextTrack; if (currentTrack) { nextTrack = textTracks.filter((textTrack) => subtitleTrackMatchesTextTrack(currentTrack, textTrack))[0]; if (!nextTrack) this.warn(`Unable to find subtitle TextTrack with name "${currentTrack.name}" and language "${currentTrack.lang}"`); } [].slice.call(textTracks).forEach((track) => { if (track.mode !== "disabled" && track !== nextTrack) track.mode = "disabled"; }); if (nextTrack) { const mode = this.subtitleDisplay ? "showing" : "hidden"; if (nextTrack.mode !== mode) nextTrack.mode = mode; } } /** * This method is responsible for validating the subtitle index and periodically reloading if live. * Dispatches the SUBTITLE_TRACK_SWITCH event, which instructs the subtitle-stream-controller to load the selected track. */ setSubtitleTrack(newId) { const tracks = this.tracksInGroup; if (!this.media) { this.queuedDefaultTrack = newId; return; } if (newId < -1 || newId >= tracks.length || !isFiniteNumber(newId)) { this.warn(`Invalid subtitle track id: ${newId}`); return; } this.selectDefaultTrack = false; const lastTrack = this.currentTrack; const track = tracks[newId] || null; this.trackId = newId; this.currentTrack = track; this.toggleTrackModes(); if (!track) { this.hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id: newId }); return; } const trackLoaded = !!track.details && !track.details.live; if (newId === this.trackId && track === lastTrack && trackLoaded) return; this.log(`Switching to subtitle-track ${newId}` + (track ? ` "${track.name}" lang:${track.lang} group:${track.groupId}` : "")); const { id, groupId = "", name, type, url } = track; this.hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id, groupId, name, type, url }); const hlsUrlParameters = this.switchParams(track.url, lastTrack == null ? void 0 : lastTrack.details, track.details); this.loadPlaylist(hlsUrlParameters); } }; /** * Generate a random v4 UUID * * @returns A random v4 UUID * * @group Utils * * @beta */ function uuid() { try { return crypto.randomUUID(); } catch (error) { try { const url = URL.createObjectURL(new Blob()); const uuid = url.toString(); URL.revokeObjectURL(url); return uuid.slice(uuid.lastIndexOf("/") + 1); } catch (error) { let dt = (/* @__PURE__ */ new Date()).getTime(); return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16); return (c == "x" ? r : r & 3 | 8).toString(16); }); } } } function hash(text) { let hash = 5381; let i = text.length; while (i) hash = hash * 33 ^ text.charCodeAt(--i); return (hash >>> 0).toString(); } var ALIGNED_END_THRESHOLD_SECONDS = .025; var TimelineOccupancy = /*#__PURE__*/ function(TimelineOccupancy) { TimelineOccupancy[TimelineOccupancy["Point"] = 0] = "Point"; TimelineOccupancy[TimelineOccupancy["Range"] = 1] = "Range"; return TimelineOccupancy; }({}); function generateAssetIdentifier(interstitial, uri, assetListIndex) { return `${interstitial.identifier}-${assetListIndex + 1}-${hash(uri)}`; } var InterstitialEvent = class { constructor(dateRange, base) { this.base = void 0; this._duration = null; this._timelineStart = null; this.appendInPlaceDisabled = void 0; this.appendInPlaceStarted = void 0; this.dateRange = void 0; this.hasPlayed = false; this.cumulativeDuration = 0; this.resumeOffset = NaN; this.playoutLimit = NaN; this.restrictions = { skip: false, jump: false }; this.snapOptions = { out: false, in: false }; this.assetList = []; this.assetListLoader = void 0; this.assetListResponse = null; this.resumeAnchor = void 0; this.error = void 0; this.resetOnResume = void 0; this.base = base; this.dateRange = dateRange; this.setDateRange(dateRange); } setDateRange(dateRange) { this.dateRange = dateRange; this.resumeOffset = dateRange.attr.optionalFloat("X-RESUME-OFFSET", this.resumeOffset); this.playoutLimit = dateRange.attr.optionalFloat("X-PLAYOUT-LIMIT", this.playoutLimit); this.restrictions = dateRange.attr.enumeratedStringList("X-RESTRICT", this.restrictions); this.snapOptions = dateRange.attr.enumeratedStringList("X-SNAP", this.snapOptions); } reset() { var _this$assetListLoader; this.appendInPlaceStarted = false; (_this$assetListLoader = this.assetListLoader) == null || _this$assetListLoader.destroy(); this.assetListLoader = void 0; if (!this.supplementsPrimary) { this.assetListResponse = null; this.assetList = []; this._duration = null; } } isAssetPastPlayoutLimit(assetIndex) { var _this$assetList$asset; if (assetIndex > 0 && assetIndex >= this.assetList.length) return true; const playoutLimit = this.playoutLimit; if (assetIndex <= 0 || isNaN(playoutLimit)) return false; if (playoutLimit === 0) return true; return (((_this$assetList$asset = this.assetList[assetIndex]) == null ? void 0 : _this$assetList$asset.startOffset) || 0) > playoutLimit; } findAssetIndex(asset) { return this.assetList.indexOf(asset); } get identifier() { return this.dateRange.id; } get startDate() { return this.dateRange.startDate; } get startTime() { const startTime = this.dateRange.startTime; if (this.snapOptions.out) { const frag = this.dateRange.tagAnchor; if (frag) return getSnapToFragmentTime(startTime, frag); } return startTime; } get startOffset() { return this.cue.pre ? 0 : this.startTime; } get startIsAligned() { if (this.startTime === 0 || this.snapOptions.out) return true; const frag = this.dateRange.tagAnchor; if (frag) { const startTime = this.dateRange.startTime; return startTime - getSnapToFragmentTime(startTime, frag) < .1; } return false; } get resumptionOffset() { const resumeOffset = this.resumeOffset; const offset = isFiniteNumber(resumeOffset) ? resumeOffset : this.duration; return this.cumulativeDuration + offset; } get resumeTime() { const resumeTime = this.startOffset + this.resumptionOffset; if (this.snapOptions.in) { const frag = this.resumeAnchor; if (frag) return getSnapToFragmentTime(resumeTime, frag); } return resumeTime; } get appendInPlace() { if (this.appendInPlaceStarted) return true; if (this.appendInPlaceDisabled) return false; if (!this.cue.once && !this.cue.pre && this.startIsAligned && (isNaN(this.playoutLimit) && isNaN(this.resumeOffset) || this.resumeOffset && this.duration && Math.abs(this.resumeOffset - this.duration) < ALIGNED_END_THRESHOLD_SECONDS)) return true; return false; } set appendInPlace(value) { if (this.appendInPlaceStarted) { this.resetOnResume = !value; return; } this.appendInPlaceDisabled = !value; } get timelineStart() { if (this._timelineStart !== null) return this._timelineStart; return this.startTime; } set timelineStart(value) { this._timelineStart = value; } get duration() { const playoutLimit = this.playoutLimit; let duration; if (this._duration !== null) duration = this._duration; else if (this.dateRange.duration) duration = this.dateRange.duration; else duration = this.dateRange.plannedDuration || 0; if (!isNaN(playoutLimit) && playoutLimit < duration) duration = playoutLimit; return duration; } set duration(value) { this._duration = value; } get cue() { return this.dateRange.cue; } get timelineOccupancy() { if (this.dateRange.attr["X-TIMELINE-OCCUPIES"] === "RANGE") return TimelineOccupancy.Range; return TimelineOccupancy.Point; } get supplementsPrimary() { return this.dateRange.attr["X-TIMELINE-STYLE"] === "PRIMARY"; } get contentMayVary() { return this.dateRange.attr["X-CONTENT-MAY-VARY"] !== "NO"; } get assetUrl() { return this.dateRange.attr["X-ASSET-URI"]; } get assetListUrl() { return this.dateRange.attr["X-ASSET-LIST"]; } get baseUrl() { return this.base.url; } get assetListLoaded() { return this.assetList.length > 0 || this.assetListResponse !== null; } toString() { return eventToString(this); } }; function getSnapToFragmentTime(time, frag) { return time - frag.start < frag.duration / 2 && !(Math.abs(time - (frag.start + frag.duration)) < ALIGNED_END_THRESHOLD_SECONDS) ? frag.start : frag.start + frag.duration; } function getInterstitialUrl(uri, sessionId, baseUrl) { const url = new self.URL(uri, baseUrl); if (url.protocol !== "data:") url.searchParams.set("_HLS_primary_id", sessionId); return url; } function getNextAssetIndex(interstitial, assetListIndex) { while ((_interstitial$assetLi = interstitial.assetList[++assetListIndex]) != null && _interstitial$assetLi.error) var _interstitial$assetLi; return assetListIndex; } function eventToString(interstitial) { return `["${interstitial.identifier}" ${interstitial.cue.pre ? "
" : interstitial.cue.post ? "" : ""}${interstitial.timelineStart.toFixed(2)}-${interstitial.resumeTime.toFixed(2)}]`;
}
function eventAssetToString(asset) {
	const start = asset.timelineStart;
	const duration = asset.duration || 0;
	return `["${asset.identifier}" ${start.toFixed(2)}-${(start + duration).toFixed(2)}]`;
}
var HlsAssetPlayer = class {
	constructor(HlsPlayerClass, userConfig, interstitial, assetItem) {
		this.hls = void 0;
		this.interstitial = void 0;
		this.assetItem = void 0;
		this.tracks = null;
		this.hasDetails = false;
		this.mediaAttached = null;
		this._currentTime = void 0;
		this._bufferedEosTime = void 0;
		this.checkPlayout = () => {
			if (this.reachedPlayout(this.currentTime) && this.hls) this.hls.trigger(Events.PLAYOUT_LIMIT_REACHED, {});
		};
		const hls = this.hls = new HlsPlayerClass(userConfig);
		this.interstitial = interstitial;
		this.assetItem = assetItem;
		const detailsLoaded = () => {
			this.hasDetails = true;
		};
		hls.once(Events.LEVEL_LOADED, detailsLoaded);
		hls.once(Events.AUDIO_TRACK_LOADED, detailsLoaded);
		hls.once(Events.SUBTITLE_TRACK_LOADED, detailsLoaded);
		hls.on(Events.MEDIA_ATTACHING, (name, { media }) => {
			this.removeMediaListeners();
			this.mediaAttached = media;
			if (this.interstitial.playoutLimit) {
				media.addEventListener("timeupdate", this.checkPlayout);
				if (this.appendInPlace) hls.on(Events.BUFFER_APPENDED, () => {
					const bufferedEnd = this.bufferedEnd;
					if (this.reachedPlayout(bufferedEnd)) {
						this._bufferedEosTime = bufferedEnd;
						hls.trigger(Events.BUFFERED_TO_END, void 0);
					}
				});
			}
		});
	}
	get appendInPlace() {
		return this.interstitial.appendInPlace;
	}
	loadSource() {
		const hls = this.hls;
		if (!hls) return;
		if (!hls.url) {
			let uri = this.assetItem.uri;
			try {
				uri = getInterstitialUrl(uri, hls.config.primarySessionId || "").href;
			} catch (error) {}
			hls.loadSource(uri);
		} else if (hls.levels.length && !hls.started) hls.startLoad(-1, true);
	}
	bufferedInPlaceToEnd(media) {
		var _this$hls;
		if (!this.appendInPlace) return false;
		if ((_this$hls = this.hls) != null && _this$hls.bufferedToEnd) return true;
		if (!media) return false;
		const duration = Math.min(this._bufferedEosTime || Infinity, this.duration);
		const start = this.timelineOffset;
		const bufferInfo = BufferHelper.bufferInfo(media, start, 0);
		return this.getAssetTime(bufferInfo.end) >= duration - .02;
	}
	reachedPlayout(time) {
		const playoutLimit = this.interstitial.playoutLimit;
		return this.startOffset + time >= playoutLimit;
	}
	get destroyed() {
		var _this$hls2;
		return !((_this$hls2 = this.hls) != null && _this$hls2.userConfig);
	}
	get assetId() {
		return this.assetItem.identifier;
	}
	get interstitialId() {
		return this.assetItem.parentIdentifier;
	}
	get media() {
		var _this$hls3;
		return ((_this$hls3 = this.hls) == null ? void 0 : _this$hls3.media) || null;
	}
	get bufferedEnd() {
		const media = this.media || this.mediaAttached;
		if (!media) {
			if (this._bufferedEosTime) return this._bufferedEosTime;
			return this.currentTime;
		}
		const bufferInfo = BufferHelper.bufferInfo(media, media.currentTime, .001);
		return this.getAssetTime(bufferInfo.end);
	}
	get currentTime() {
		const media = this.media || this.mediaAttached;
		if (!media) return this._currentTime || 0;
		return this.getAssetTime(media.currentTime);
	}
	get duration() {
		const duration = this.assetItem.duration;
		if (!duration) return 0;
		const playoutLimit = this.interstitial.playoutLimit;
		if (playoutLimit) {
			const assetPlayout = playoutLimit - this.startOffset;
			if (assetPlayout > 0 && assetPlayout < duration) return assetPlayout;
		}
		return duration;
	}
	get remaining() {
		const duration = this.duration;
		if (!duration) return 0;
		return Math.max(0, duration - this.currentTime);
	}
	get startOffset() {
		return this.assetItem.startOffset;
	}
	get timelineOffset() {
		var _this$hls4;
		return ((_this$hls4 = this.hls) == null ? void 0 : _this$hls4.config.timelineOffset) || 0;
	}
	set timelineOffset(value) {
		const timelineOffset = this.timelineOffset;
		if (value !== timelineOffset) {
			const diff = value - timelineOffset;
			if (Math.abs(diff) > 1 / 9e4 && this.hls) {
				if (this.hasDetails) throw new Error(`Cannot set timelineOffset after playlists are loaded`);
				this.hls.config.timelineOffset = value;
			}
		}
	}
	getAssetTime(time) {
		const timelineOffset = this.timelineOffset;
		const duration = this.duration;
		return Math.min(Math.max(0, time - timelineOffset), duration);
	}
	removeMediaListeners() {
		const media = this.mediaAttached;
		if (media) {
			this._currentTime = media.currentTime;
			this.bufferSnapShot();
			media.removeEventListener("timeupdate", this.checkPlayout);
		}
	}
	bufferSnapShot() {
		if (this.mediaAttached) {
			var _this$hls5;
			if ((_this$hls5 = this.hls) != null && _this$hls5.bufferedToEnd) this._bufferedEosTime = this.bufferedEnd;
		}
	}
	destroy() {
		this.removeMediaListeners();
		if (this.hls) this.hls.destroy();
		this.hls = null;
		this.tracks = this.mediaAttached = this.checkPlayout = null;
	}
	attachMedia(data) {
		var _this$hls6;
		this.loadSource();
		(_this$hls6 = this.hls) == null || _this$hls6.attachMedia(data);
	}
	detachMedia() {
		var _this$hls7;
		this.removeMediaListeners();
		this.mediaAttached = null;
		(_this$hls7 = this.hls) == null || _this$hls7.detachMedia();
	}
	resumeBuffering() {
		var _this$hls8;
		(_this$hls8 = this.hls) == null || _this$hls8.resumeBuffering();
	}
	pauseBuffering() {
		var _this$hls9;
		(_this$hls9 = this.hls) == null || _this$hls9.pauseBuffering();
	}
	transferMedia() {
		var _this$hls0;
		this.bufferSnapShot();
		return ((_this$hls0 = this.hls) == null ? void 0 : _this$hls0.transferMedia()) || null;
	}
	resetDetails() {
		const hls = this.hls;
		if (hls && this.hasDetails) {
			hls.stopLoad();
			const deleteDetails = (obj) => delete obj.details;
			hls.levels.forEach(deleteDetails);
			hls.allAudioTracks.forEach(deleteDetails);
			hls.allSubtitleTracks.forEach(deleteDetails);
			this.hasDetails = false;
		}
	}
	on(event, listener, context) {
		var _this$hls1;
		(_this$hls1 = this.hls) == null || _this$hls1.on(event, listener);
	}
	once(event, listener, context) {
		var _this$hls10;
		(_this$hls10 = this.hls) == null || _this$hls10.once(event, listener);
	}
	off(event, listener, context) {
		var _this$hls11;
		(_this$hls11 = this.hls) == null || _this$hls11.off(event, listener);
	}
	toString() {
		var _this$hls12;
		return `HlsAssetPlayer: ${eventAssetToString(this.assetItem)} ${(_this$hls12 = this.hls) == null ? void 0 : _this$hls12.sessionId} ${this.appendInPlace ? "append-in-place" : ""}`;
	}
};
var ABUTTING_THRESHOLD_SECONDS = .033;
var InterstitialsSchedule = class extends Logger {
	constructor(onScheduleUpdate, logger) {
		super("interstitials-sched", logger);
		this.onScheduleUpdate = void 0;
		this.eventMap = {};
		this.events = null;
		this.items = null;
		this.durations = {
			primary: 0,
			playout: 0,
			integrated: 0
		};
		this.onScheduleUpdate = onScheduleUpdate;
	}
	destroy() {
		this.reset();
		this.onScheduleUpdate = null;
	}
	reset() {
		this.eventMap = {};
		this.setDurations(0, 0, 0);
		if (this.events) this.events.forEach((interstitial) => interstitial.reset());
		this.events = this.items = null;
	}
	resetErrorsInRange(start, end) {
		if (this.events) return this.events.reduce((count, interstitial) => {
			if (start <= interstitial.startOffset && end > interstitial.startOffset) {
				delete interstitial.error;
				return count + 1;
			}
			return count;
		}, 0);
		return 0;
	}
	get duration() {
		const items = this.items;
		return items ? items[items.length - 1].end : 0;
	}
	get length() {
		return this.items ? this.items.length : 0;
	}
	getEvent(identifier) {
		return identifier ? this.eventMap[identifier] || null : null;
	}
	hasEvent(identifier) {
		return identifier in this.eventMap;
	}
	findItemIndex(item, time) {
		if (item.event) return this.findEventIndex(item.event.identifier);
		let index = -1;
		if (item.nextEvent) index = this.findEventIndex(item.nextEvent.identifier) - 1;
		else if (item.previousEvent) index = this.findEventIndex(item.previousEvent.identifier) + 1;
		const items = this.items;
		if (items) {
			if (!items[index]) {
				if (time === void 0) time = item.start;
				index = this.findItemIndexAtTime(time);
			}
			while (index >= 0 && (_items$index = items[index]) != null && _items$index.event) {
				var _items$index;
				index--;
			}
		}
		return index;
	}
	findItemIndexAtTime(timelinePos, timelineType) {
		const items = this.items;
		if (items) for (let i = 0; i < items.length; i++) {
			let timeRange = items[i];
			if (timelineType && timelineType !== "primary") timeRange = timeRange[timelineType];
			if (timelinePos === timeRange.start || timelinePos > timeRange.start && timelinePos < timeRange.end) return i;
		}
		return -1;
	}
	findJumpRestrictedIndex(startIndex, endIndex) {
		const items = this.items;
		if (items) for (let i = startIndex; i <= endIndex; i++) {
			if (!items[i]) break;
			const event = items[i].event;
			if (event != null && event.restrictions.jump && !event.appendInPlace) return i;
		}
		return -1;
	}
	findEventIndex(identifier) {
		const items = this.items;
		if (items) for (let i = items.length; i--;) {
			var _items$i$event;
			if (((_items$i$event = items[i].event) == null ? void 0 : _items$i$event.identifier) === identifier) return i;
		}
		return -1;
	}
	findAssetIndex(event, timelinePos) {
		const assetList = event.assetList;
		const length = assetList.length;
		if (length > 1) for (let i = 0; i < length; i++) {
			const asset = assetList[i];
			if (!asset.error) {
				const timelineStart = asset.timelineStart;
				if (timelinePos === timelineStart || timelinePos > timelineStart && (timelinePos < timelineStart + (asset.duration || 0) || i === length - 1)) return i;
			}
		}
		return 0;
	}
	get assetIdAtEnd() {
		var _this$items;
		const interstitialAtEnd = (_this$items = this.items) == null || (_this$items = _this$items[this.length - 1]) == null ? void 0 : _this$items.event;
		if (interstitialAtEnd) {
			const assetList = interstitialAtEnd.assetList;
			const assetAtEnd = assetList[assetList.length - 1];
			if (assetAtEnd) return assetAtEnd.identifier;
		}
		return null;
	}
	parseInterstitialDateRanges(mediaSelection, enableAppendInPlace) {
		const details = mediaSelection.main.details;
		const { dateRanges } = details;
		const previousInterstitialEvents = this.events;
		const interstitialEvents = this.parseDateRanges(dateRanges, { url: details.url }, enableAppendInPlace);
		const ids = Object.keys(dateRanges);
		const removedInterstitials = previousInterstitialEvents ? previousInterstitialEvents.filter((event) => !ids.includes(event.identifier)) : [];
		if (interstitialEvents.length) interstitialEvents.sort((a, b) => {
			const aPre = a.cue.pre;
			const aPost = a.cue.post;
			const bPre = b.cue.pre;
			const bPost = b.cue.post;
			if (aPre && !bPre) return -1;
			if (bPre && !aPre) return 1;
			if (aPost && !bPost) return 1;
			if (bPost && !aPost) return -1;
			if (!aPre && !bPre && !aPost && !bPost) {
				const startA = a.startTime;
				const startB = b.startTime;
				if (startA !== startB) return startA - startB;
			}
			return a.dateRange.tagOrder - b.dateRange.tagOrder;
		});
		this.events = interstitialEvents;
		removedInterstitials.forEach((interstitial) => {
			this.removeEvent(interstitial);
		});
		this.updateSchedule(mediaSelection, removedInterstitials);
	}
	updateSchedule(mediaSelection, removedInterstitials = [], forceUpdate = false) {
		const events = this.events || [];
		if (events.length || removedInterstitials.length || this.length < 2) {
			const currentItems = this.items;
			const updatedItems = this.parseSchedule(events, mediaSelection);
			if (forceUpdate || removedInterstitials.length || (currentItems == null ? void 0 : currentItems.length) !== updatedItems.length || updatedItems.some((item, i) => {
				return Math.abs(item.playout.start - currentItems[i].playout.start) > .005 || Math.abs(item.playout.end - currentItems[i].playout.end) > .005;
			})) {
				this.items = updatedItems;
				this.onScheduleUpdate(removedInterstitials, currentItems);
			}
		}
	}
	parseDateRanges(dateRanges, baseData, enableAppendInPlace) {
		const interstitialEvents = [];
		const ids = Object.keys(dateRanges);
		for (let i = 0; i < ids.length; i++) {
			const id = ids[i];
			const dateRange = dateRanges[id];
			if (dateRange.isInterstitial) {
				let interstitial = this.eventMap[id];
				if (interstitial) interstitial.setDateRange(dateRange);
				else {
					interstitial = new InterstitialEvent(dateRange, baseData);
					this.eventMap[id] = interstitial;
					if (enableAppendInPlace === false) interstitial.appendInPlace = enableAppendInPlace;
				}
				interstitialEvents.push(interstitial);
			}
		}
		return interstitialEvents;
	}
	parseSchedule(interstitialEvents, mediaSelection) {
		const schedule = [];
		const details = mediaSelection.main.details;
		const primaryDuration = details.live ? Infinity : details.edge;
		let playoutDuration = 0;
		interstitialEvents = interstitialEvents.filter((event) => !event.error && !(event.cue.once && event.hasPlayed));
		if (interstitialEvents.length) {
			this.resolveOffsets(interstitialEvents, mediaSelection);
			let primaryPosition = 0;
			let integratedTime = 0;
			interstitialEvents.forEach((interstitial, i) => {
				const preroll = interstitial.cue.pre;
				const postroll = interstitial.cue.post;
				const previousEvent = interstitialEvents[i - 1] || null;
				const appendInPlace = interstitial.appendInPlace;
				const eventStart = postroll ? primaryDuration : interstitial.startOffset;
				const interstitialDuration = interstitial.duration;
				const timelineDuration = interstitial.timelineOccupancy === TimelineOccupancy.Range ? interstitialDuration : 0;
				const resumptionOffset = interstitial.resumptionOffset;
				const inSameStartTimeSequence = (previousEvent == null ? void 0 : previousEvent.startTime) === eventStart;
				const start = eventStart + interstitial.cumulativeDuration;
				let end = appendInPlace ? start + interstitialDuration : eventStart + resumptionOffset;
				if (preroll || !postroll && eventStart <= 0) {
					const integratedStart = integratedTime;
					integratedTime += timelineDuration;
					interstitial.timelineStart = start;
					const playoutStart = playoutDuration;
					playoutDuration += interstitialDuration;
					schedule.push({
						event: interstitial,
						start,
						end,
						playout: {
							start: playoutStart,
							end: playoutDuration
						},
						integrated: {
							start: integratedStart,
							end: integratedTime
						}
					});
				} else if (eventStart <= primaryDuration) {
					if (!inSameStartTimeSequence) {
						const segmentDuration = eventStart - primaryPosition;
						if (segmentDuration > ABUTTING_THRESHOLD_SECONDS) {
							const timelineStart = primaryPosition;
							const _integratedStart = integratedTime;
							integratedTime += segmentDuration;
							const _playoutStart = playoutDuration;
							playoutDuration += segmentDuration;
							const primarySegment = {
								previousEvent: interstitialEvents[i - 1] || null,
								nextEvent: interstitial,
								start: timelineStart,
								end: timelineStart + segmentDuration,
								playout: {
									start: _playoutStart,
									end: playoutDuration
								},
								integrated: {
									start: _integratedStart,
									end: integratedTime
								}
							};
							schedule.push(primarySegment);
						} else if (segmentDuration > 0 && previousEvent) {
							previousEvent.cumulativeDuration += segmentDuration;
							schedule[schedule.length - 1].end = eventStart;
						}
					}
					if (postroll) end = start;
					interstitial.timelineStart = start;
					const integratedStart = integratedTime;
					integratedTime += timelineDuration;
					const playoutStart = playoutDuration;
					playoutDuration += interstitialDuration;
					schedule.push({
						event: interstitial,
						start,
						end,
						playout: {
							start: playoutStart,
							end: playoutDuration
						},
						integrated: {
							start: integratedStart,
							end: integratedTime
						}
					});
				} else return;
				const resumeTime = interstitial.resumeTime;
				if (postroll || resumeTime > primaryDuration) primaryPosition = primaryDuration;
				else primaryPosition = resumeTime;
			});
			if (primaryPosition < primaryDuration) {
				var _schedule;
				const timelineStart = primaryPosition;
				const integratedStart = integratedTime;
				const segmentDuration = primaryDuration - primaryPosition;
				integratedTime += segmentDuration;
				const playoutStart = playoutDuration;
				playoutDuration += segmentDuration;
				schedule.push({
					previousEvent: ((_schedule = schedule[schedule.length - 1]) == null ? void 0 : _schedule.event) || null,
					nextEvent: null,
					start: primaryPosition,
					end: timelineStart + segmentDuration,
					playout: {
						start: playoutStart,
						end: playoutDuration
					},
					integrated: {
						start: integratedStart,
						end: integratedTime
					}
				});
			}
			this.setDurations(primaryDuration, playoutDuration, integratedTime);
		} else {
			const start = 0;
			schedule.push({
				previousEvent: null,
				nextEvent: null,
				start,
				end: primaryDuration,
				playout: {
					start,
					end: primaryDuration
				},
				integrated: {
					start,
					end: primaryDuration
				}
			});
			this.setDurations(primaryDuration, primaryDuration, primaryDuration);
		}
		return schedule;
	}
	setDurations(primary, playout, integrated) {
		this.durations = {
			primary,
			playout,
			integrated
		};
	}
	resolveOffsets(interstitialEvents, mediaSelection) {
		const details = mediaSelection.main.details;
		const primaryDuration = details.live ? Infinity : details.edge;
		let cumulativeDuration = 0;
		let lastScheduledStart = -1;
		interstitialEvents.forEach((interstitial, i) => {
			const preroll = interstitial.cue.pre;
			const postroll = interstitial.cue.post;
			const eventStart = preroll ? 0 : postroll ? primaryDuration : interstitial.startTime;
			this.updateAssetDurations(interstitial);
			if (lastScheduledStart === eventStart) interstitial.cumulativeDuration = cumulativeDuration;
			else {
				cumulativeDuration = 0;
				lastScheduledStart = eventStart;
			}
			if (!postroll && interstitial.snapOptions.in) interstitial.resumeAnchor = findFragmentByPTS(null, details.fragments, interstitial.startOffset + interstitial.resumptionOffset, 0, 0) || void 0;
			if (interstitial.appendInPlace && !interstitial.appendInPlaceStarted) {
				if (!this.primaryCanResumeInPlaceAt(interstitial, mediaSelection)) interstitial.appendInPlace = false;
			}
			if (!interstitial.appendInPlace && i + 1 < interstitialEvents.length) {
				if (interstitialEvents[i + 1].startTime - interstitialEvents[i].resumeTime < ABUTTING_THRESHOLD_SECONDS) {
					interstitialEvents[i + 1].appendInPlace = false;
					if (interstitialEvents[i + 1].appendInPlace) this.warn(`Could not change append strategy for abutting event ${interstitial}`);
				}
			}
			const resumeOffset = isFiniteNumber(interstitial.resumeOffset) ? interstitial.resumeOffset : interstitial.duration;
			cumulativeDuration += resumeOffset;
		});
	}
	primaryCanResumeInPlaceAt(interstitial, mediaSelection) {
		const resumeTime = interstitial.resumeTime;
		const resumesInPlaceAt = interstitial.startTime + interstitial.resumptionOffset;
		if (Math.abs(resumeTime - resumesInPlaceAt) > ALIGNED_END_THRESHOLD_SECONDS) {
			this.log(`"${interstitial.identifier}" resumption ${resumeTime} not aligned with estimated timeline end ${resumesInPlaceAt}`);
			return false;
		}
		return !Object.keys(mediaSelection).some((playlistType) => {
			const details = mediaSelection[playlistType].details;
			const playlistEnd = details.edge;
			if (resumeTime >= playlistEnd) {
				this.log(`"${interstitial.identifier}" resumption ${resumeTime} past ${playlistType} playlist end ${playlistEnd}`);
				return false;
			}
			const startFragment = findFragmentByPTS(null, details.fragments, resumeTime);
			if (!startFragment) {
				this.log(`"${interstitial.identifier}" resumption ${resumeTime} does not align with any fragments in ${playlistType} playlist (${details.fragStart}-${details.fragmentEnd})`);
				return true;
			}
			const allowance = playlistType === "audio" ? .175 : 0;
			if (!(Math.abs(startFragment.start - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS + allowance || Math.abs(startFragment.end - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS + allowance)) {
				this.log(`"${interstitial.identifier}" resumption ${resumeTime} not aligned with ${playlistType} fragment bounds (${startFragment.start}-${startFragment.end} sn: ${startFragment.sn} cc: ${startFragment.cc})`);
				return true;
			}
			return false;
		});
	}
	updateAssetDurations(interstitial) {
		if (!interstitial.assetListLoaded) return;
		const eventStart = interstitial.timelineStart;
		let sumDuration = 0;
		let hasUnknownDuration = false;
		let hasErrors = false;
		for (let i = 0; i < interstitial.assetList.length; i++) {
			const asset = interstitial.assetList[i];
			const timelineStart = eventStart + sumDuration;
			asset.startOffset = sumDuration;
			asset.timelineStart = timelineStart;
			hasUnknownDuration || (hasUnknownDuration = asset.duration === null);
			hasErrors || (hasErrors = !!asset.error);
			const duration = asset.error ? 0 : asset.duration || 0;
			sumDuration += duration;
		}
		if (hasUnknownDuration && !hasErrors) interstitial.duration = Math.max(sumDuration, interstitial.duration);
		else interstitial.duration = sumDuration;
	}
	removeEvent(interstitial) {
		interstitial.reset();
		delete this.eventMap[interstitial.identifier];
	}
};
function segmentToString(segment) {
	return `[${segment.event ? "\"" + segment.event.identifier + "\"" : "primary"}: ${segment.start.toFixed(2)}-${segment.end.toFixed(2)}]`;
}
var AssetListLoader = class {
	constructor(hls) {
		this.hls = void 0;
		this.hls = hls;
	}
	destroy() {
		this.hls = null;
	}
	loadAssetList(interstitial, hlsStartOffset) {
		const assetListUrl = interstitial.assetListUrl;
		let url;
		try {
			url = getInterstitialUrl(assetListUrl, this.hls.sessionId, interstitial.baseUrl);
		} catch (error) {
			const errorData = this.assignAssetListError(interstitial, ErrorDetails.ASSET_LIST_LOAD_ERROR, error, assetListUrl);
			this.hls.trigger(Events.ERROR, errorData);
			return;
		}
		if (hlsStartOffset && url.protocol !== "data:") url.searchParams.set("_HLS_start_offset", "" + hlsStartOffset);
		const config = this.hls.config;
		const Loader = config.loader;
		const loader = new Loader(config);
		const context = {
			responseType: "json",
			url: url.href
		};
		const loadPolicy = config.interstitialAssetListLoadPolicy.default;
		const loaderConfig = {
			loadPolicy,
			timeout: loadPolicy.maxLoadTimeMs,
			maxRetry: 0,
			retryDelay: 0,
			maxRetryDelay: 0
		};
		loader.load(context, loaderConfig, {
			onSuccess: (response, stats, context, networkDetails) => {
				const assetListResponse = response.data;
				const assets = assetListResponse == null ? void 0 : assetListResponse.ASSETS;
				if (!Array.isArray(assets)) {
					const errorData = this.assignAssetListError(interstitial, ErrorDetails.ASSET_LIST_PARSING_ERROR, /* @__PURE__ */ new Error(`Invalid interstitial asset list`), context.url, stats, networkDetails);
					this.hls.trigger(Events.ERROR, errorData);
					return;
				}
				interstitial.assetListResponse = assetListResponse;
				this.hls.trigger(Events.ASSET_LIST_LOADED, {
					event: interstitial,
					assetListResponse,
					networkDetails
				});
			},
			onError: (error, context, networkDetails, stats) => {
				const errorData = this.assignAssetListError(interstitial, ErrorDetails.ASSET_LIST_LOAD_ERROR, /* @__PURE__ */ new Error(`Error loading X-ASSET-LIST: HTTP status ${error.code} ${error.text} (${context.url})`), context.url, stats, networkDetails);
				this.hls.trigger(Events.ERROR, errorData);
			},
			onTimeout: (stats, context, networkDetails) => {
				const errorData = this.assignAssetListError(interstitial, ErrorDetails.ASSET_LIST_LOAD_TIMEOUT, /* @__PURE__ */ new Error(`Timeout loading X-ASSET-LIST (${context.url})`), context.url, stats, networkDetails);
				this.hls.trigger(Events.ERROR, errorData);
			}
		});
		this.hls.trigger(Events.ASSET_LIST_LOADING, { event: interstitial });
		return loader;
	}
	assignAssetListError(interstitial, details, error, url, stats, networkDetails) {
		interstitial.error = error;
		return {
			type: ErrorTypes.NETWORK_ERROR,
			details,
			fatal: false,
			interstitial,
			url,
			error,
			networkDetails,
			stats
		};
	}
};
function playWithCatch(media) {
	var _media$play;
	media == null || (_media$play = media.play()) == null || _media$play.catch(() => {});
}
function timelineMessage(label, time) {
	return `[${label}] Advancing timeline position to ${time}`;
}
var InterstitialsController = class extends Logger {
	constructor(hls, HlsPlayerClass) {
		super("interstitials", hls.logger);
		this.HlsPlayerClass = void 0;
		this.hls = void 0;
		this.assetListLoader = void 0;
		this.mediaSelection = null;
		this.altSelection = null;
		this.media = null;
		this.detachedData = null;
		this.requiredTracks = null;
		this.manager = null;
		this.playerQueue = [];
		this.bufferedPos = -1;
		this.timelinePos = -1;
		this.schedule = void 0;
		this.playingItem = null;
		this.bufferingItem = null;
		this.waitingItem = null;
		this.endedItem = null;
		this.playingAsset = null;
		this.endedAsset = null;
		this.bufferingAsset = null;
		this.shouldPlay = false;
		this.onPlay = () => {
			this.shouldPlay = true;
		};
		this.onPause = () => {
			this.shouldPlay = false;
		};
		this.onSeeking = () => {
			const currentTime = this.currentTime;
			if (currentTime === void 0 || this.playbackDisabled || !this.schedule) return;
			const diff = currentTime - this.timelinePos;
			if (Math.abs(diff) < 1 / 7056e5) return;
			const backwardSeek = diff <= -.01;
			if (this.timelinePos === -1 && !this.effectivePlayingItem) this.checkStart();
			this.timelinePos = currentTime;
			this.bufferedPos = currentTime;
			const playingItem = this.playingItem;
			if (!playingItem) {
				this.checkBuffer();
				return;
			}
			if (backwardSeek) {
				if (this.schedule.resetErrorsInRange(currentTime, currentTime - diff)) this.updateSchedule(true);
			}
			this.checkBuffer();
			if (backwardSeek && currentTime < playingItem.start || currentTime >= playingItem.end) {
				var _this$media;
				const playingIndex = this.findItemIndex(playingItem);
				let scheduleIndex = this.schedule.findItemIndexAtTime(currentTime);
				if (scheduleIndex === -1) {
					scheduleIndex = playingIndex + (backwardSeek ? -1 : 1);
					this.log(`seeked ${backwardSeek ? "back " : ""}to position not covered by schedule ${currentTime} (resolving from ${playingIndex} to ${scheduleIndex})`);
				}
				if (!this.isInterstitial(playingItem) && (_this$media = this.media) != null && _this$media.paused) this.shouldPlay = false;
				if (!backwardSeek) {
					if (scheduleIndex > playingIndex) {
						const jumpIndex = this.schedule.findJumpRestrictedIndex(playingIndex + 1, scheduleIndex);
						if (jumpIndex > playingIndex) {
							this.setSchedulePosition(jumpIndex);
							return;
						}
					}
				}
				this.setSchedulePosition(scheduleIndex);
				return;
			}
			const playingAsset = this.playingAsset;
			if (!playingAsset) {
				if (this.playingLastItem && this.isInterstitial(playingItem)) {
					const restartAsset = playingItem.event.assetList[0];
					if (restartAsset) {
						this.endedItem = this.playingItem;
						this.playingItem = null;
						this.setScheduleToAssetAtTime(currentTime, restartAsset);
					}
				}
				return;
			}
			const start = playingAsset.timelineStart;
			const duration = playingAsset.duration || 0;
			if (backwardSeek && currentTime < start || currentTime >= start + duration) {
				var _playingItem$event;
				if ((_playingItem$event = playingItem.event) != null && _playingItem$event.appendInPlace) {
					this.clearAssetPlayers(playingItem.event, playingItem);
					this.flushFrontBuffer(currentTime);
				}
				this.setScheduleToAssetAtTime(currentTime, playingAsset);
			}
		};
		this.onTimeupdate = () => {
			const currentTime = this.currentTime;
			if (currentTime === void 0 || this.playbackDisabled) return;
			if (this.timelinePos === -1 && !this.effectivePlayingItem) this.checkStart();
			if (currentTime > this.timelinePos) {
				this.timelinePos = currentTime;
				if (currentTime > this.bufferedPos) this.checkBuffer();
			} else return;
			const playingItem = this.playingItem;
			if (!playingItem || this.playingLastItem) return;
			if (currentTime >= playingItem.end) {
				this.timelinePos = playingItem.end;
				const playingIndex = this.findItemIndex(playingItem);
				this.setSchedulePosition(playingIndex + 1);
			}
			const playingAsset = this.playingAsset;
			if (!playingAsset) return;
			if (currentTime >= playingAsset.timelineStart + (playingAsset.duration || 0)) this.setScheduleToAssetAtTime(currentTime, playingAsset);
		};
		this.onScheduleUpdate = (removedInterstitials, previousItems) => {
			const schedule = this.schedule;
			if (!schedule) return;
			const playingItem = this.playingItem;
			const interstitialEvents = schedule.events || [];
			const scheduleItems = schedule.items || [];
			const durations = schedule.durations;
			const removedIds = removedInterstitials.map((interstitial) => interstitial.identifier);
			const interstitialsUpdated = !!(interstitialEvents.length || removedIds.length);
			if (interstitialsUpdated || previousItems) this.log(`INTERSTITIALS_UPDATED (${interstitialEvents.length}): ${interstitialEvents}
Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timelinePos}`);
			if (removedIds.length) this.log(`Removed events ${removedIds}`);
			let updatedPlayingItem = null;
			let updatedBufferingItem = null;
			if (playingItem) {
				updatedPlayingItem = this.updateItem(playingItem, this.timelinePos);
				if (this.itemsMatch(playingItem, updatedPlayingItem)) this.playingItem = updatedPlayingItem;
				else this.waitingItem = this.endedItem = null;
			}
			this.waitingItem = this.updateItem(this.waitingItem);
			this.endedItem = this.updateItem(this.endedItem);
			const bufferingItem = this.bufferingItem;
			if (bufferingItem) {
				updatedBufferingItem = this.updateItem(bufferingItem, this.bufferedPos);
				if (this.itemsMatch(bufferingItem, updatedBufferingItem)) this.bufferingItem = updatedBufferingItem;
				else if (bufferingItem.event) {
					this.bufferingItem = this.playingItem;
					this.clearInterstitial(bufferingItem.event, null);
				}
			}
			removedInterstitials.forEach((interstitial) => {
				interstitial.assetList.forEach((asset) => {
					this.clearAssetPlayer(asset.identifier, null);
				});
			});
			this.playerQueue.forEach((player) => {
				if (player.interstitial.appendInPlace) {
					const timelineStart = player.assetItem.timelineStart;
					const diff = player.timelineOffset - timelineStart;
					if (diff) try {
						player.timelineOffset = timelineStart;
					} catch (e) {
						if (Math.abs(diff) > ALIGNED_END_THRESHOLD_SECONDS) this.warn(`${e} ("${player.assetId}" ${player.timelineOffset}->${timelineStart})`);
					}
				}
			});
			if (interstitialsUpdated || previousItems) {
				this.hls.trigger(Events.INTERSTITIALS_UPDATED, {
					events: interstitialEvents.slice(0),
					schedule: scheduleItems.slice(0),
					durations,
					removedIds
				});
				if (this.isInterstitial(playingItem) && removedIds.includes(playingItem.event.identifier)) {
					this.warn(`Interstitial "${playingItem.event.identifier}" removed while playing`);
					this.primaryFallback(playingItem.event);
					return;
				}
				if (playingItem) this.trimInPlace(updatedPlayingItem, playingItem);
				if (bufferingItem && updatedBufferingItem !== updatedPlayingItem) this.trimInPlace(updatedBufferingItem, bufferingItem);
				this.checkBuffer();
			}
		};
		this.hls = hls;
		this.HlsPlayerClass = HlsPlayerClass;
		this.assetListLoader = new AssetListLoader(hls);
		this.schedule = new InterstitialsSchedule(this.onScheduleUpdate, hls.logger);
		this.registerListeners();
	}
	registerListeners() {
		const hls = this.hls;
		if (hls) {
			hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
			hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
			hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
			hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
			hls.on(Events.AUDIO_TRACK_UPDATED, this.onAudioTrackUpdated, this);
			hls.on(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
			hls.on(Events.SUBTITLE_TRACK_UPDATED, this.onSubtitleTrackUpdated, this);
			hls.on(Events.EVENT_CUE_ENTER, this.onInterstitialCueEnter, this);
			hls.on(Events.ASSET_LIST_LOADED, this.onAssetListLoaded, this);
			hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this);
			hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
			hls.on(Events.BUFFERED_TO_END, this.onBufferedToEnd, this);
			hls.on(Events.MEDIA_ENDED, this.onMediaEnded, this);
			hls.on(Events.ERROR, this.onError, this);
			hls.on(Events.DESTROYING, this.onDestroying, this);
		}
	}
	unregisterListeners() {
		const hls = this.hls;
		if (hls) {
			hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
			hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
			hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
			hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
			hls.off(Events.AUDIO_TRACK_UPDATED, this.onAudioTrackUpdated, this);
			hls.off(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
			hls.off(Events.SUBTITLE_TRACK_UPDATED, this.onSubtitleTrackUpdated, this);
			hls.off(Events.EVENT_CUE_ENTER, this.onInterstitialCueEnter, this);
			hls.off(Events.ASSET_LIST_LOADED, this.onAssetListLoaded, this);
			hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this);
			hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this);
			hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
			hls.off(Events.BUFFERED_TO_END, this.onBufferedToEnd, this);
			hls.off(Events.MEDIA_ENDED, this.onMediaEnded, this);
			hls.off(Events.ERROR, this.onError, this);
			hls.off(Events.DESTROYING, this.onDestroying, this);
		}
	}
	startLoad() {
		this.resumeBuffering();
	}
	stopLoad() {
		this.pauseBuffering();
	}
	resumeBuffering() {
		var _this$getBufferingPla;
		(_this$getBufferingPla = this.getBufferingPlayer()) == null || _this$getBufferingPla.resumeBuffering();
	}
	pauseBuffering() {
		var _this$getBufferingPla2;
		(_this$getBufferingPla2 = this.getBufferingPlayer()) == null || _this$getBufferingPla2.pauseBuffering();
	}
	destroy() {
		this.unregisterListeners();
		this.stopLoad();
		if (this.assetListLoader) this.assetListLoader.destroy();
		this.emptyPlayerQueue();
		this.clearScheduleState();
		if (this.schedule) this.schedule.destroy();
		this.media = this.detachedData = this.mediaSelection = this.requiredTracks = this.altSelection = this.schedule = this.manager = null;
		this.hls = this.HlsPlayerClass = this.log = null;
		this.assetListLoader = null;
		this.onPlay = this.onPause = this.onSeeking = this.onTimeupdate = null;
		this.onScheduleUpdate = null;
	}
	onDestroying() {
		const media = this.primaryMedia || this.media;
		if (media) this.removeMediaListeners(media);
	}
	removeMediaListeners(media) {
		removeEventListener(media, "play", this.onPlay);
		removeEventListener(media, "pause", this.onPause);
		removeEventListener(media, "seeking", this.onSeeking);
		removeEventListener(media, "timeupdate", this.onTimeupdate);
	}
	onMediaAttaching(event, data) {
		const media = this.media = data.media;
		addEventListener(media, "seeking", this.onSeeking);
		addEventListener(media, "timeupdate", this.onTimeupdate);
		addEventListener(media, "play", this.onPlay);
		addEventListener(media, "pause", this.onPause);
	}
	onMediaAttached(event, data) {
		const playingItem = this.effectivePlayingItem;
		const detachedMedia = this.detachedData;
		this.detachedData = null;
		if (playingItem === null) this.checkStart();
		else if (!detachedMedia) {
			this.clearScheduleState();
			const playingIndex = this.findItemIndex(playingItem);
			this.setSchedulePosition(playingIndex);
		}
	}
	clearScheduleState() {
		this.log(`clear schedule state`);
		this.playingItem = this.bufferingItem = this.waitingItem = this.endedItem = this.playingAsset = this.endedAsset = this.bufferingAsset = null;
	}
	onMediaDetaching(event, data) {
		const transferringMedia = !!data.transferMedia;
		const media = this.media;
		this.media = null;
		if (transferringMedia) return;
		if (media) this.removeMediaListeners(media);
		if (this.detachedData) {
			const player = this.getBufferingPlayer();
			if (player) {
				this.log(`Removing schedule state for detachedData and ${player}`);
				this.playingAsset = this.endedAsset = this.bufferingAsset = this.bufferingItem = this.waitingItem = this.detachedData = null;
				player.detachMedia();
			}
			this.shouldPlay = false;
		}
	}
	get interstitialsManager() {
		if (!this.hls) return null;
		if (this.manager) return this.manager;
		const c = this;
		const effectiveBufferingItem = () => c.bufferingItem || c.waitingItem;
		const getAssetPlayer = (asset) => asset ? c.getAssetPlayer(asset.identifier) : asset;
		const getMappedTime = (item, timelineType, asset, controllerField, assetPlayerField) => {
			if (item) {
				let time = item[timelineType].start;
				const interstitial = item.event;
				if (interstitial) {
					if (timelineType === "playout" || interstitial.timelineOccupancy !== TimelineOccupancy.Point) {
						const assetPlayer = getAssetPlayer(asset);
						if ((assetPlayer == null ? void 0 : assetPlayer.interstitial) === interstitial) time += assetPlayer.assetItem.startOffset + assetPlayer[assetPlayerField];
					}
				} else {
					const value = controllerField === "bufferedPos" ? getBufferedEnd() : c[controllerField];
					time += value - item.start;
				}
				return time;
			}
			return 0;
		};
		const findMappedTime = (primaryTime, timelineType) => {
			var _c$schedule;
			if (primaryTime !== 0 && timelineType !== "primary" && (_c$schedule = c.schedule) != null && _c$schedule.length) {
				var _c$schedule$items;
				const index = c.schedule.findItemIndexAtTime(primaryTime);
				const item = (_c$schedule$items = c.schedule.items) == null ? void 0 : _c$schedule$items[index];
				if (item) return primaryTime + (item[timelineType].start - item.start);
			}
			return primaryTime;
		};
		const getBufferedEnd = () => {
			const value = c.bufferedPos;
			if (value === Number.MAX_VALUE) return getMappedDuration("primary");
			return Math.max(value, 0);
		};
		const getMappedDuration = (timelineType) => {
			var _c$primaryDetails, _c$schedule2;
			if ((_c$primaryDetails = c.primaryDetails) != null && _c$primaryDetails.live) return c.primaryDetails.edge;
			return ((_c$schedule2 = c.schedule) == null ? void 0 : _c$schedule2.durations[timelineType]) || 0;
		};
		const seekTo = (time, timelineType) => {
			var _item$event, _c$schedule$items2;
			const item = c.effectivePlayingItem;
			if (item != null && (_item$event = item.event) != null && _item$event.restrictions.skip || !c.schedule) return;
			c.log(`seek to ${time} "${timelineType}"`);
			const playingItem = c.effectivePlayingItem;
			const targetIndex = c.schedule.findItemIndexAtTime(time, timelineType);
			const targetItem = (_c$schedule$items2 = c.schedule.items) == null ? void 0 : _c$schedule$items2[targetIndex];
			const bufferingPlayer = c.getBufferingPlayer();
			const bufferingInterstitial = bufferingPlayer == null ? void 0 : bufferingPlayer.interstitial;
			const appendInPlace = bufferingInterstitial == null ? void 0 : bufferingInterstitial.appendInPlace;
			const seekInItem = playingItem && c.itemsMatch(playingItem, targetItem);
			if (playingItem && (appendInPlace || seekInItem)) {
				const assetPlayer = getAssetPlayer(c.playingAsset);
				const media = (assetPlayer == null ? void 0 : assetPlayer.media) || c.primaryMedia;
				if (media) {
					const currentTime = timelineType === "primary" ? media.currentTime : getMappedTime(playingItem, timelineType, c.playingAsset, "timelinePos", "currentTime");
					const diff = time - currentTime;
					const seekToTime = (appendInPlace ? currentTime : media.currentTime) + diff;
					if (seekToTime >= 0 && (!assetPlayer || appendInPlace || seekToTime <= assetPlayer.duration)) {
						media.currentTime = seekToTime;
						return;
					}
				}
			}
			if (targetItem) {
				let seekToTime = time;
				if (timelineType !== "primary") {
					const diff = time - targetItem[timelineType].start;
					seekToTime = targetItem.start + diff;
				}
				const targetIsPrimary = !c.isInterstitial(targetItem);
				if ((!c.isInterstitial(playingItem) || playingItem.event.appendInPlace) && (targetIsPrimary || targetItem.event.appendInPlace)) {
					const media = c.media || (appendInPlace ? bufferingPlayer == null ? void 0 : bufferingPlayer.media : null);
					if (media) media.currentTime = seekToTime;
				} else if (playingItem) {
					const playingIndex = c.findItemIndex(playingItem);
					if (targetIndex > playingIndex) {
						const jumpIndex = c.schedule.findJumpRestrictedIndex(playingIndex + 1, targetIndex);
						if (jumpIndex > playingIndex) {
							c.setSchedulePosition(jumpIndex);
							return;
						}
					}
					let assetIndex = 0;
					if (targetIsPrimary) {
						c.timelinePos = seekToTime;
						c.checkBuffer();
					} else {
						const assetList = targetItem.event.assetList;
						const eventTime = time - (targetItem[timelineType] || targetItem).start;
						for (let i = assetList.length; i--;) {
							const asset = assetList[i];
							if (asset.duration && eventTime >= asset.startOffset && eventTime < asset.startOffset + asset.duration) {
								assetIndex = i;
								break;
							}
						}
					}
					c.setSchedulePosition(targetIndex, assetIndex);
				}
			}
		};
		const getActiveInterstitial = () => {
			const playingItem = c.effectivePlayingItem;
			if (c.isInterstitial(playingItem)) return playingItem;
			const bufferingItem = effectiveBufferingItem();
			if (c.isInterstitial(bufferingItem)) return bufferingItem;
			return null;
		};
		const interstitialPlayer = {
			get bufferedEnd() {
				const interstitialItem = effectiveBufferingItem();
				const bufferingItem = c.bufferingItem;
				if (bufferingItem && bufferingItem === interstitialItem) {
					var _c$bufferingAsset;
					return getMappedTime(bufferingItem, "playout", c.bufferingAsset, "bufferedPos", "bufferedEnd") - bufferingItem.playout.start || ((_c$bufferingAsset = c.bufferingAsset) == null ? void 0 : _c$bufferingAsset.startOffset) || 0;
				}
				return 0;
			},
			get currentTime() {
				const interstitialItem = getActiveInterstitial();
				const playingItem = c.effectivePlayingItem;
				if (playingItem && playingItem === interstitialItem) return getMappedTime(playingItem, "playout", c.effectivePlayingAsset, "timelinePos", "currentTime") - playingItem.playout.start;
				return 0;
			},
			set currentTime(time) {
				const interstitialItem = getActiveInterstitial();
				const playingItem = c.effectivePlayingItem;
				if (playingItem && playingItem === interstitialItem) seekTo(time + playingItem.playout.start, "playout");
			},
			get duration() {
				const interstitialItem = getActiveInterstitial();
				if (interstitialItem) return interstitialItem.playout.end - interstitialItem.playout.start;
				return 0;
			},
			get assetPlayers() {
				var _getActiveInterstitia;
				const assetList = (_getActiveInterstitia = getActiveInterstitial()) == null ? void 0 : _getActiveInterstitia.event.assetList;
				if (assetList) return assetList.map((asset) => c.getAssetPlayer(asset.identifier));
				return [];
			},
			get playingIndex() {
				var _getActiveInterstitia2;
				const interstitial = (_getActiveInterstitia2 = getActiveInterstitial()) == null ? void 0 : _getActiveInterstitia2.event;
				if (interstitial && c.effectivePlayingAsset) return interstitial.findAssetIndex(c.effectivePlayingAsset);
				return -1;
			},
			get scheduleItem() {
				return getActiveInterstitial();
			}
		};
		return this.manager = {
			get events() {
				var _c$schedule3;
				return ((_c$schedule3 = c.schedule) == null || (_c$schedule3 = _c$schedule3.events) == null ? void 0 : _c$schedule3.slice(0)) || [];
			},
			get schedule() {
				var _c$schedule4;
				return ((_c$schedule4 = c.schedule) == null || (_c$schedule4 = _c$schedule4.items) == null ? void 0 : _c$schedule4.slice(0)) || [];
			},
			get interstitialPlayer() {
				if (getActiveInterstitial()) return interstitialPlayer;
				return null;
			},
			get playerQueue() {
				return c.playerQueue.slice(0);
			},
			get bufferingAsset() {
				return c.bufferingAsset;
			},
			get bufferingItem() {
				return effectiveBufferingItem();
			},
			get bufferingIndex() {
				const item = effectiveBufferingItem();
				return c.findItemIndex(item);
			},
			get playingAsset() {
				return c.effectivePlayingAsset;
			},
			get playingItem() {
				return c.effectivePlayingItem;
			},
			get playingIndex() {
				const item = c.effectivePlayingItem;
				return c.findItemIndex(item);
			},
			primary: {
				get bufferedEnd() {
					return getBufferedEnd();
				},
				get currentTime() {
					const timelinePos = c.timelinePos;
					return timelinePos > 0 ? timelinePos : 0;
				},
				set currentTime(time) {
					seekTo(time, "primary");
				},
				get duration() {
					return getMappedDuration("primary");
				},
				get seekableStart() {
					var _c$primaryDetails2;
					return ((_c$primaryDetails2 = c.primaryDetails) == null ? void 0 : _c$primaryDetails2.fragmentStart) || 0;
				}
			},
			integrated: {
				get bufferedEnd() {
					return getMappedTime(effectiveBufferingItem(), "integrated", c.bufferingAsset, "bufferedPos", "bufferedEnd");
				},
				get currentTime() {
					return getMappedTime(c.effectivePlayingItem, "integrated", c.effectivePlayingAsset, "timelinePos", "currentTime");
				},
				set currentTime(time) {
					seekTo(time, "integrated");
				},
				get duration() {
					return getMappedDuration("integrated");
				},
				get seekableStart() {
					var _c$primaryDetails3;
					return findMappedTime(((_c$primaryDetails3 = c.primaryDetails) == null ? void 0 : _c$primaryDetails3.fragmentStart) || 0, "integrated");
				}
			},
			skip: () => {
				const item = c.effectivePlayingItem;
				const event = item == null ? void 0 : item.event;
				if (event && !event.restrictions.skip) {
					const index = c.findItemIndex(item);
					if (event.appendInPlace) seekTo(item.playout.start + item.event.duration + .001, "playout");
					else c.advanceAfterAssetEnded(event, index, Infinity);
				}
			}
		};
	}
	get effectivePlayingItem() {
		return this.waitingItem || this.playingItem || this.endedItem;
	}
	get effectivePlayingAsset() {
		return this.playingAsset || this.endedAsset;
	}
	get playingLastItem() {
		var _this$schedule;
		const playingItem = this.playingItem;
		const items = (_this$schedule = this.schedule) == null ? void 0 : _this$schedule.items;
		if (!this.playbackStarted || !playingItem || !items) return false;
		return this.findItemIndex(playingItem) === items.length - 1;
	}
	get playbackStarted() {
		return this.effectivePlayingItem !== null;
	}
	get currentTime() {
		var _this$bufferingItem, _media;
		if (this.mediaSelection === null) return;
		const queuedForPlayback = this.waitingItem || this.playingItem;
		if (this.isInterstitial(queuedForPlayback) && !queuedForPlayback.event.appendInPlace) return;
		let media = this.media;
		if (!media && (_this$bufferingItem = this.bufferingItem) != null && (_this$bufferingItem = _this$bufferingItem.event) != null && _this$bufferingItem.appendInPlace) media = this.primaryMedia;
		const currentTime = (_media = media) == null ? void 0 : _media.currentTime;
		if (currentTime === void 0 || !isFiniteNumber(currentTime)) return;
		return currentTime;
	}
	get primaryMedia() {
		var _this$detachedData;
		return this.media || ((_this$detachedData = this.detachedData) == null ? void 0 : _this$detachedData.media) || null;
	}
	isInterstitial(item) {
		return !!(item != null && item.event);
	}
	retreiveMediaSource(assetId, toSegment) {
		const player = this.getAssetPlayer(assetId);
		if (player) this.transferMediaFromPlayer(player, toSegment);
	}
	transferMediaFromPlayer(player, toSegment) {
		const appendInPlace = player.interstitial.appendInPlace;
		const playerMedia = player.media;
		if (appendInPlace && playerMedia === this.primaryMedia) {
			this.bufferingAsset = null;
			if (!toSegment || this.isInterstitial(toSegment) && !toSegment.event.appendInPlace) {
				if (toSegment && playerMedia) {
					this.detachedData = { media: playerMedia };
					return;
				}
			}
			const attachMediaSourceData = player.transferMedia();
			this.log(`transfer MediaSource from ${player} ${stringify(attachMediaSourceData)}`);
			this.detachedData = attachMediaSourceData;
		} else if (toSegment && playerMedia) this.shouldPlay || (this.shouldPlay = !playerMedia.paused);
	}
	transferMediaTo(player, media) {
		var _this$detachedData2, _attachMediaSourceDat;
		if (player.media === media) return;
		let attachMediaSourceData = null;
		const primaryPlayer = this.hls;
		const isAssetPlayer = player !== primaryPlayer;
		const appendInPlace = isAssetPlayer && player.interstitial.appendInPlace;
		const detachedMediaSource = (_this$detachedData2 = this.detachedData) == null ? void 0 : _this$detachedData2.mediaSource;
		let logFromSource;
		if (primaryPlayer.media) {
			if (appendInPlace) {
				attachMediaSourceData = primaryPlayer.transferMedia();
				this.detachedData = attachMediaSourceData;
			}
			logFromSource = `Primary`;
		} else if (detachedMediaSource) {
			const bufferingPlayer = this.getBufferingPlayer();
			if (bufferingPlayer) {
				attachMediaSourceData = bufferingPlayer.transferMedia();
				logFromSource = `${bufferingPlayer}`;
			} else logFromSource = `detached MediaSource`;
		} else logFromSource = `detached media`;
		if (!attachMediaSourceData) {
			if (detachedMediaSource) {
				attachMediaSourceData = this.detachedData;
				this.log(`using detachedData: MediaSource ${stringify(attachMediaSourceData)}`);
			} else if (!this.detachedData || primaryPlayer.media === media) {
				const playerQueue = this.playerQueue;
				if (playerQueue.length > 1) playerQueue.forEach((queuedPlayer) => {
					if (isAssetPlayer && queuedPlayer.interstitial.appendInPlace !== appendInPlace) {
						const interstitial = queuedPlayer.interstitial;
						this.clearInterstitial(queuedPlayer.interstitial, null);
						interstitial.appendInPlace = false;
						if (interstitial.appendInPlace) this.warn(`Could not change append strategy for queued assets ${interstitial}`);
					}
				});
				this.hls.detachMedia();
				this.detachedData = { media };
			}
		}
		const transferring = attachMediaSourceData && "mediaSource" in attachMediaSourceData && ((_attachMediaSourceDat = attachMediaSourceData.mediaSource) == null ? void 0 : _attachMediaSourceDat.readyState) !== "closed";
		const dataToAttach = transferring && attachMediaSourceData ? attachMediaSourceData : media;
		this.log(`${transferring ? "transfering MediaSource" : "attaching media"} to ${isAssetPlayer ? player : "Primary"} from ${logFromSource} (media.currentTime: ${media.currentTime})`);
		const schedule = this.schedule;
		if (dataToAttach === attachMediaSourceData && schedule) {
			const isAssetAtEndOfSchedule = isAssetPlayer && player.assetId === schedule.assetIdAtEnd;
			dataToAttach.overrides = {
				duration: schedule.duration,
				endOfStream: !isAssetPlayer || isAssetAtEndOfSchedule,
				cueRemoval: !isAssetPlayer
			};
		}
		player.attachMedia(dataToAttach);
	}
	onInterstitialCueEnter() {
		this.onTimeupdate();
	}
	checkStart() {
		const schedule = this.schedule;
		const interstitialEvents = schedule == null ? void 0 : schedule.events;
		if (!interstitialEvents || this.playbackDisabled || !this.media) return;
		if (this.bufferedPos === -1) this.bufferedPos = 0;
		const timelinePos = this.timelinePos;
		const effectivePlayingItem = this.effectivePlayingItem;
		if (timelinePos === -1) {
			const startPosition = this.hls.startPosition;
			this.timelinePos = startPosition;
			if (interstitialEvents.length === 0) this.setSchedulePosition(0);
			else if (interstitialEvents[0].cue.pre) {
				this.log(timelineMessage("checkStart (preroll)", startPosition));
				const index = schedule.findEventIndex(interstitialEvents[0].identifier);
				this.setSchedulePosition(index);
			} else if (startPosition >= 0 || !this.primaryLive) {
				this.log(timelineMessage("checkStart", startPosition));
				const start = this.timelinePos = startPosition > 0 ? startPosition : 0;
				const index = schedule.findItemIndexAtTime(start);
				this.setSchedulePosition(index);
			} else if (this.hls.liveSyncPosition === 0) this.setSchedulePosition(0);
			else this.log("[checkStart] waiting for live start");
		} else if (effectivePlayingItem && !this.playingItem) {
			this.log(timelineMessage("checkStart (playing item)", effectivePlayingItem.start));
			const index = schedule.findItemIndex(effectivePlayingItem);
			this.setSchedulePosition(index);
		}
	}
	advanceAssetBuffering(item, assetItem) {
		const interstitial = item.event;
		const nextAssetIndex = getNextAssetIndex(interstitial, interstitial.findAssetIndex(assetItem));
		if (!interstitial.isAssetPastPlayoutLimit(nextAssetIndex)) this.bufferedToEvent(item, nextAssetIndex);
		else if (this.schedule) {
			var _this$schedule$items;
			const nextItem = (_this$schedule$items = this.schedule.items) == null ? void 0 : _this$schedule$items[this.findItemIndex(item) + 1];
			if (nextItem) this.bufferedToItem(nextItem);
		}
	}
	advanceAfterAssetEnded(interstitial, index, assetListIndex) {
		const nextAssetIndex = getNextAssetIndex(interstitial, assetListIndex);
		if (!interstitial.isAssetPastPlayoutLimit(nextAssetIndex)) {
			if (interstitial.appendInPlace) {
				const assetItem = interstitial.assetList[nextAssetIndex];
				if (assetItem) this.advanceInPlace(assetItem.timelineStart);
			}
			this.setSchedulePosition(index, nextAssetIndex);
		} else if (this.schedule) {
			const scheduleItems = this.schedule.items;
			if (scheduleItems) {
				const nextIndex = index + 1;
				if (nextIndex >= scheduleItems.length) {
					this.setSchedulePosition(-1);
					return;
				}
				const resumptionTime = interstitial.resumeTime;
				if (this.timelinePos < resumptionTime) {
					this.log(timelineMessage("advanceAfterAssetEnded", resumptionTime));
					this.timelinePos = resumptionTime;
					if (interstitial.appendInPlace) this.advanceInPlace(resumptionTime);
					this.checkBuffer(this.bufferedPos < resumptionTime);
				}
				this.setSchedulePosition(nextIndex);
			}
		}
	}
	setScheduleToAssetAtTime(time, playingAsset) {
		const schedule = this.schedule;
		if (!schedule) return;
		const parentIdentifier = playingAsset.parentIdentifier;
		const interstitial = schedule.getEvent(parentIdentifier);
		if (interstitial) {
			const itemIndex = schedule.findEventIndex(parentIdentifier);
			const assetListIndex = schedule.findAssetIndex(interstitial, time);
			this.advanceAfterAssetEnded(interstitial, itemIndex, assetListIndex - 1);
		}
	}
	setSchedulePosition(index, assetListIndex) {
		var _this$schedule2;
		const scheduleItems = (_this$schedule2 = this.schedule) == null ? void 0 : _this$schedule2.items;
		if (!scheduleItems || this.playbackDisabled) return;
		const scheduledItem = index >= 0 ? scheduleItems[index] : null;
		this.log(`setSchedulePosition ${index}, ${assetListIndex} (${scheduledItem ? segmentToString(scheduledItem) : scheduledItem}) pos: ${this.timelinePos}`);
		const currentItem = this.waitingItem || this.playingItem;
		const playingLastItem = this.playingLastItem;
		if (this.isInterstitial(currentItem)) {
			const interstitial = currentItem.event;
			const playingAsset = this.playingAsset;
			const assetId = playingAsset == null ? void 0 : playingAsset.identifier;
			const player = assetId ? this.getAssetPlayer(assetId) : null;
			if (player && assetId && (!this.eventItemsMatch(currentItem, scheduledItem) || assetListIndex !== void 0 && assetId !== interstitial.assetList[assetListIndex].identifier)) {
				var _this$detachedData3;
				const playingAssetListIndex = interstitial.findAssetIndex(playingAsset);
				this.log(`INTERSTITIAL_ASSET_ENDED ${playingAssetListIndex + 1}/${interstitial.assetList.length} ${eventAssetToString(playingAsset)}`);
				this.endedAsset = playingAsset;
				this.playingAsset = null;
				this.hls.trigger(Events.INTERSTITIAL_ASSET_ENDED, {
					asset: playingAsset,
					assetListIndex: playingAssetListIndex,
					event: interstitial,
					schedule: scheduleItems.slice(0),
					scheduleIndex: index,
					player
				});
				if (currentItem !== this.playingItem) {
					if (this.itemsMatch(currentItem, this.playingItem) && !this.playingAsset) this.advanceAfterAssetEnded(interstitial, this.findItemIndex(this.playingItem), playingAssetListIndex);
					return;
				}
				this.retreiveMediaSource(assetId, scheduledItem);
				if (player.media && !((_this$detachedData3 = this.detachedData) != null && _this$detachedData3.mediaSource)) player.detachMedia();
			}
			if (!this.eventItemsMatch(currentItem, scheduledItem)) {
				this.endedItem = currentItem;
				this.playingItem = null;
				this.log(`INTERSTITIAL_ENDED ${interstitial} ${segmentToString(currentItem)}`);
				interstitial.hasPlayed = true;
				this.hls.trigger(Events.INTERSTITIAL_ENDED, {
					event: interstitial,
					schedule: scheduleItems.slice(0),
					scheduleIndex: index
				});
				if (interstitial.cue.once) {
					var _this$schedule3;
					this.updateSchedule();
					const updatedScheduleItems = (_this$schedule3 = this.schedule) == null ? void 0 : _this$schedule3.items;
					if (scheduledItem && updatedScheduleItems) {
						const updatedIndex = this.findItemIndex(scheduledItem);
						this.advanceSchedule(updatedIndex, updatedScheduleItems, assetListIndex, currentItem, playingLastItem);
					}
					return;
				}
			}
		}
		this.advanceSchedule(index, scheduleItems, assetListIndex, currentItem, playingLastItem);
	}
	advanceSchedule(index, scheduleItems, assetListIndex, currentItem, playedLastItem) {
		const schedule = this.schedule;
		if (!schedule) return;
		const scheduledItem = scheduleItems[index] || null;
		const media = this.primaryMedia;
		const playerQueue = this.playerQueue;
		if (playerQueue.length) playerQueue.forEach((player) => {
			const interstitial = player.interstitial;
			const queuedIndex = schedule.findEventIndex(interstitial.identifier);
			if (queuedIndex < index || queuedIndex > index + 1) this.clearInterstitial(interstitial, scheduledItem);
		});
		if (this.isInterstitial(scheduledItem)) {
			this.timelinePos = Math.min(Math.max(this.timelinePos, scheduledItem.start), scheduledItem.end);
			const interstitial = scheduledItem.event;
			if (assetListIndex === void 0) {
				assetListIndex = schedule.findAssetIndex(interstitial, this.timelinePos);
				const assetIndexCandidate = getNextAssetIndex(interstitial, assetListIndex - 1);
				if (interstitial.isAssetPastPlayoutLimit(assetIndexCandidate) || interstitial.appendInPlace && this.timelinePos === scheduledItem.end) {
					this.advanceAfterAssetEnded(interstitial, index, assetListIndex);
					return;
				}
				assetListIndex = assetIndexCandidate;
			}
			const waitingItem = this.waitingItem;
			if (!this.assetsBuffered(scheduledItem, media)) this.setBufferingItem(scheduledItem);
			let player = this.preloadAssets(interstitial, assetListIndex);
			if (!this.eventItemsMatch(scheduledItem, waitingItem || currentItem)) {
				this.waitingItem = scheduledItem;
				this.log(`INTERSTITIAL_STARTED ${segmentToString(scheduledItem)} ${interstitial.appendInPlace ? "append in place" : ""}`);
				this.hls.trigger(Events.INTERSTITIAL_STARTED, {
					event: interstitial,
					schedule: scheduleItems.slice(0),
					scheduleIndex: index
				});
			}
			if (!interstitial.assetListLoaded) {
				this.log(`Waiting for ASSET-LIST to complete loading ${interstitial}`);
				return;
			}
			if (interstitial.assetListLoader) {
				interstitial.assetListLoader.destroy();
				interstitial.assetListLoader = void 0;
			}
			if (!media) {
				this.log(`Waiting for attachMedia to start Interstitial ${interstitial}`);
				return;
			}
			this.waitingItem = this.endedItem = null;
			this.playingItem = scheduledItem;
			const assetItem = interstitial.assetList[assetListIndex];
			if (!assetItem) {
				this.advanceAfterAssetEnded(interstitial, index, assetListIndex || 0);
				return;
			}
			if (!player) player = this.getAssetPlayer(assetItem.identifier);
			if (player === null || player.destroyed) {
				const assetListLength = interstitial.assetList.length;
				this.warn(`asset ${assetListIndex + 1}/${assetListLength} player destroyed ${interstitial}`);
				player = this.createAssetPlayer(interstitial, assetItem, assetListIndex);
				player.loadSource();
			}
			if (!this.eventItemsMatch(scheduledItem, this.bufferingItem)) {
				if (interstitial.appendInPlace && this.isAssetBuffered(assetItem)) return;
			}
			this.startAssetPlayer(player, assetListIndex, scheduleItems, index, media);
			if (this.shouldPlay) playWithCatch(player.media);
		} else if (scheduledItem) {
			this.resumePrimary(scheduledItem, index, currentItem);
			if (this.shouldPlay) playWithCatch(this.hls.media);
		} else if (playedLastItem && this.isInterstitial(currentItem)) {
			this.endedItem = null;
			this.playingItem = currentItem;
			if (!currentItem.event.appendInPlace) this.attachPrimary(schedule.durations.primary, null);
		}
	}
	get playbackDisabled() {
		return this.hls.config.enableInterstitialPlayback === false;
	}
	get primaryDetails() {
		var _this$mediaSelection;
		return (_this$mediaSelection = this.mediaSelection) == null ? void 0 : _this$mediaSelection.main.details;
	}
	get primaryLive() {
		var _this$primaryDetails;
		return !!((_this$primaryDetails = this.primaryDetails) != null && _this$primaryDetails.live);
	}
	resumePrimary(scheduledItem, index, fromItem) {
		var _this$detachedData4, _this$schedule4;
		this.playingItem = scheduledItem;
		this.playingAsset = this.endedAsset = null;
		this.waitingItem = this.endedItem = null;
		this.bufferedToItem(scheduledItem);
		this.log(`resuming ${segmentToString(scheduledItem)}`);
		if (!((_this$detachedData4 = this.detachedData) != null && _this$detachedData4.mediaSource)) {
			let timelinePos = this.timelinePos;
			if (timelinePos < scheduledItem.start || timelinePos >= scheduledItem.end) {
				timelinePos = this.getPrimaryResumption(scheduledItem, index);
				this.log(timelineMessage("resumePrimary", timelinePos));
				this.timelinePos = timelinePos;
			}
			this.attachPrimary(timelinePos, scheduledItem);
		}
		if (!fromItem) return;
		const scheduleItems = (_this$schedule4 = this.schedule) == null ? void 0 : _this$schedule4.items;
		if (!scheduleItems) return;
		this.log(`INTERSTITIALS_PRIMARY_RESUMED ${segmentToString(scheduledItem)}`);
		this.hls.trigger(Events.INTERSTITIALS_PRIMARY_RESUMED, {
			schedule: scheduleItems.slice(0),
			scheduleIndex: index
		});
		this.checkBuffer();
	}
	getPrimaryResumption(scheduledItem, index) {
		const itemStart = scheduledItem.start;
		if (this.primaryLive) {
			const details = this.primaryDetails;
			if (index === 0) return this.hls.startPosition;
			else if (details && (itemStart < details.fragmentStart || itemStart > details.edge)) return this.hls.liveSyncPosition || -1;
		}
		return itemStart;
	}
	isAssetBuffered(asset) {
		const player = this.getAssetPlayer(asset.identifier);
		if (player != null && player.hls) return player.hls.bufferedToEnd;
		return BufferHelper.bufferInfo(this.primaryMedia, this.timelinePos, 0).end + 1 >= asset.timelineStart + (asset.duration || 0);
	}
	attachPrimary(timelinePos, item, skipSeekToStartPosition) {
		if (item) this.setBufferingItem(item);
		else this.bufferingItem = this.playingItem;
		this.bufferingAsset = null;
		const media = this.primaryMedia;
		if (!media) return;
		const hls = this.hls;
		if (hls.media) this.checkBuffer();
		else {
			this.transferMediaTo(hls, media);
			if (skipSeekToStartPosition) this.startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition);
		}
		if (!skipSeekToStartPosition) {
			this.log(timelineMessage("attachPrimary", timelinePos));
			this.timelinePos = timelinePos;
			this.startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition);
		}
	}
	startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition) {
		var _hls$mainForwardBuffe;
		const hls = this.hls;
		if (!hls.loadingEnabled || !hls.media || Math.abs((((_hls$mainForwardBuffe = hls.mainForwardBufferInfo) == null ? void 0 : _hls$mainForwardBuffe.start) || hls.media.currentTime) - timelinePos) > .5) hls.startLoad(timelinePos, skipSeekToStartPosition);
		else if (!hls.bufferingEnabled) hls.resumeBuffering();
	}
	onManifestLoading() {
		var _this$schedule5;
		this.stopLoad();
		(_this$schedule5 = this.schedule) == null || _this$schedule5.reset();
		this.emptyPlayerQueue();
		this.clearScheduleState();
		this.shouldPlay = false;
		this.bufferedPos = this.timelinePos = -1;
		this.mediaSelection = this.altSelection = this.manager = this.requiredTracks = null;
		this.hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this);
		this.hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this);
	}
	onLevelUpdated(event, data) {
		if (data.level === -1 || !this.schedule) return;
		const main = this.hls.levels[data.level];
		if (!main.details) return;
		const currentSelection = _objectSpread2(_objectSpread2({}, this.mediaSelection || this.altSelection), {}, { main });
		this.mediaSelection = currentSelection;
		this.schedule.parseInterstitialDateRanges(currentSelection, this.hls.config.interstitialAppendInPlace);
		if (!this.effectivePlayingItem && this.schedule.items) this.checkStart();
	}
	onAudioTrackUpdated(event, data) {
		const audio = this.hls.audioTracks[data.id];
		const previousSelection = this.mediaSelection;
		if (!previousSelection) {
			this.altSelection = _objectSpread2(_objectSpread2({}, this.altSelection), {}, { audio });
			return;
		}
		const currentSelection = _objectSpread2(_objectSpread2({}, previousSelection), {}, { audio });
		this.mediaSelection = currentSelection;
	}
	onSubtitleTrackUpdated(event, data) {
		const subtitles = this.hls.subtitleTracks[data.id];
		const previousSelection = this.mediaSelection;
		if (!previousSelection) {
			this.altSelection = _objectSpread2(_objectSpread2({}, this.altSelection), {}, { subtitles });
			return;
		}
		const currentSelection = _objectSpread2(_objectSpread2({}, previousSelection), {}, { subtitles });
		this.mediaSelection = currentSelection;
	}
	onAudioTrackSwitching(event, data) {
		const audioOption = getBasicSelectionOption(data);
		this.playerQueue.forEach(({ hls }) => hls && (hls.setAudioOption(data) || hls.setAudioOption(audioOption)));
	}
	onSubtitleTrackSwitch(event, data) {
		const subtitleOption = getBasicSelectionOption(data);
		this.playerQueue.forEach(({ hls }) => hls && (hls.setSubtitleOption(data) || data.id !== -1 && hls.setSubtitleOption(subtitleOption)));
	}
	onBufferCodecs(event, data) {
		const requiredTracks = data.tracks;
		if (requiredTracks) this.requiredTracks = requiredTracks;
	}
	onBufferAppended(event, data) {
		this.checkBuffer();
	}
	onBufferFlushed(event, data) {
		const playingItem = this.playingItem;
		if (playingItem && !this.itemsMatch(playingItem, this.bufferingItem) && !this.isInterstitial(playingItem)) {
			const timelinePos = this.timelinePos;
			this.bufferedPos = timelinePos;
			this.checkBuffer();
		}
	}
	onBufferedToEnd(event) {
		if (!this.schedule) return;
		const interstitialEvents = this.schedule.events;
		if (this.bufferedPos < Number.MAX_VALUE && interstitialEvents) {
			for (let i = 0; i < interstitialEvents.length; i++) {
				const interstitial = interstitialEvents[i];
				if (interstitial.cue.post) {
					var _this$schedule$items2;
					const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
					const item = (_this$schedule$items2 = this.schedule.items) == null ? void 0 : _this$schedule$items2[scheduleIndex];
					if (this.isInterstitial(item) && this.eventItemsMatch(item, this.bufferingItem)) this.bufferedToItem(item, 0);
					break;
				}
			}
			this.bufferedPos = Number.MAX_VALUE;
		}
	}
	onMediaEnded(event) {
		const playingItem = this.playingItem;
		if (!this.playingLastItem && playingItem) {
			const playingIndex = this.findItemIndex(playingItem);
			this.setSchedulePosition(playingIndex + 1);
		} else this.shouldPlay = false;
	}
	updateItem(previousItem, time) {
		var _this$schedule6;
		const items = (_this$schedule6 = this.schedule) == null ? void 0 : _this$schedule6.items;
		if (previousItem && items) return items[this.findItemIndex(previousItem, time)] || null;
		return null;
	}
	trimInPlace(updatedItem, itemBeforeUpdate) {
		if (this.isInterstitial(updatedItem) && updatedItem.event.appendInPlace && itemBeforeUpdate.end - updatedItem.end > .25) {
			updatedItem.event.assetList.forEach((asset, index) => {
				if (updatedItem.event.isAssetPastPlayoutLimit(index)) this.clearAssetPlayer(asset.identifier, null);
			});
			const flushStart = updatedItem.end + .25;
			const bufferInfo = BufferHelper.bufferInfo(this.primaryMedia, flushStart, 0);
			if (bufferInfo.end > flushStart || (bufferInfo.nextStart || 0) > flushStart) {
				this.log(`trim buffered interstitial ${segmentToString(updatedItem)} (was ${segmentToString(itemBeforeUpdate)})`);
				this.attachPrimary(flushStart, null, true);
				this.flushFrontBuffer(flushStart);
			}
		}
	}
	itemsMatch(a, b) {
		return !!b && (a === b || a.event && b.event && this.eventItemsMatch(a, b) || !a.event && !b.event && this.findItemIndex(a) === this.findItemIndex(b));
	}
	eventItemsMatch(a, b) {
		var _b$event;
		return !!b && (a === b || a.event.identifier === ((_b$event = b.event) == null ? void 0 : _b$event.identifier));
	}
	findItemIndex(item, time) {
		return item && this.schedule ? this.schedule.findItemIndex(item, time) : -1;
	}
	updateSchedule(forceUpdate = false) {
		var _this$schedule7;
		const mediaSelection = this.mediaSelection;
		if (!mediaSelection) return;
		(_this$schedule7 = this.schedule) == null || _this$schedule7.updateSchedule(mediaSelection, [], forceUpdate);
	}
	checkBuffer(starved) {
		var _this$schedule8;
		const items = (_this$schedule8 = this.schedule) == null ? void 0 : _this$schedule8.items;
		if (!items) return;
		const bufferInfo = BufferHelper.bufferInfo(this.primaryMedia, this.timelinePos, 0);
		if (starved) this.bufferedPos = this.timelinePos;
		starved || (starved = bufferInfo.len < 1);
		this.updateBufferedPos(bufferInfo.end, items, starved);
	}
	updateBufferedPos(bufferEnd, items, bufferIsEmpty) {
		const schedule = this.schedule;
		const bufferingItem = this.bufferingItem;
		if (this.bufferedPos > bufferEnd || !schedule) return;
		if (items.length === 1 && this.itemsMatch(items[0], bufferingItem)) {
			this.bufferedPos = bufferEnd;
			return;
		}
		const playingItem = this.playingItem;
		const playingIndex = this.findItemIndex(playingItem);
		let bufferEndIndex = schedule.findItemIndexAtTime(bufferEnd);
		if (this.bufferedPos < bufferEnd) {
			var _nextItemToBuffer$eve;
			const bufferingIndex = this.findItemIndex(bufferingItem);
			const nextToBufferIndex = Math.min(bufferingIndex + 1, items.length - 1);
			const nextItemToBuffer = items[nextToBufferIndex];
			if (bufferEndIndex === -1 && bufferingItem && bufferEnd >= bufferingItem.end || (_nextItemToBuffer$eve = nextItemToBuffer.event) != null && _nextItemToBuffer$eve.appendInPlace && bufferEnd + .01 >= nextItemToBuffer.start) bufferEndIndex = nextToBufferIndex;
			if (this.isInterstitial(bufferingItem)) {
				const interstitial = bufferingItem.event;
				if (nextToBufferIndex - playingIndex > 1 && interstitial.appendInPlace === false) return;
				if (interstitial.assetList.length === 0 && interstitial.assetListLoader) return;
			}
			this.bufferedPos = bufferEnd;
			if (bufferEndIndex > bufferingIndex && bufferEndIndex > playingIndex) this.bufferedToItem(nextItemToBuffer);
			else {
				const details = this.primaryDetails;
				if (this.primaryLive && details && bufferEnd > details.edge - details.targetduration && nextItemToBuffer.start < details.edge + this.hls.config.interstitialLiveLookAhead && this.isInterstitial(nextItemToBuffer)) this.preloadAssets(nextItemToBuffer.event, 0);
			}
		} else if (bufferIsEmpty && playingItem && !this.itemsMatch(playingItem, bufferingItem)) {
			if (bufferEndIndex === playingIndex) this.bufferedToItem(playingItem);
			else if (bufferEndIndex === playingIndex + 1) this.bufferedToItem(items[bufferEndIndex]);
		}
	}
	assetsBuffered(item, media) {
		if (item.event.assetList.length === 0) return false;
		return !item.event.assetList.some((asset) => {
			const player = this.getAssetPlayer(asset.identifier);
			return !(player != null && player.bufferedInPlaceToEnd(media));
		});
	}
	setBufferingItem(item) {
		const bufferingLast = this.bufferingItem;
		const schedule = this.schedule;
		if (!this.itemsMatch(item, bufferingLast) && schedule) {
			const { items, events } = schedule;
			if (!items || !events) return bufferingLast;
			const isInterstitial = this.isInterstitial(item);
			const bufferingPlayer = this.getBufferingPlayer();
			this.bufferingItem = item;
			this.bufferedPos = Math.max(item.start, Math.min(item.end, this.timelinePos));
			const timeRemaining = bufferingPlayer ? bufferingPlayer.remaining : bufferingLast ? bufferingLast.end - this.timelinePos : 0;
			this.log(`INTERSTITIALS_BUFFERED_TO_BOUNDARY ${segmentToString(item)}` + (bufferingLast ? ` (${timeRemaining.toFixed(2)} remaining)` : ""));
			if (!this.playbackDisabled) if (isInterstitial) {
				const bufferIndex = schedule.findAssetIndex(item.event, this.bufferedPos);
				item.event.assetList.forEach((asset, i) => {
					const player = this.getAssetPlayer(asset.identifier);
					if (player) {
						if (i === bufferIndex) player.loadSource();
						player.resumeBuffering();
					}
				});
			} else {
				this.hls.resumeBuffering();
				this.playerQueue.forEach((player) => player.pauseBuffering());
			}
			this.hls.trigger(Events.INTERSTITIALS_BUFFERED_TO_BOUNDARY, {
				events: events.slice(0),
				schedule: items.slice(0),
				bufferingIndex: this.findItemIndex(item),
				playingIndex: this.findItemIndex(this.playingItem)
			});
		} else if (this.bufferingItem !== item) this.bufferingItem = item;
		return bufferingLast;
	}
	bufferedToItem(item, assetListIndex = 0) {
		const bufferingLast = this.setBufferingItem(item);
		if (this.playbackDisabled) return;
		if (this.isInterstitial(item)) this.bufferedToEvent(item, assetListIndex);
		else if (bufferingLast !== null) {
			this.bufferingAsset = null;
			const detachedData = this.detachedData;
			if (detachedData) if (detachedData.mediaSource) this.attachPrimary(item.start, item, true);
			else this.preloadPrimary(item);
			else this.preloadPrimary(item);
		}
	}
	preloadPrimary(item) {
		const index = this.findItemIndex(item);
		const timelinePos = this.getPrimaryResumption(item, index);
		this.startLoadingPrimaryAt(timelinePos);
	}
	bufferedToEvent(item, assetListIndex) {
		const interstitial = item.event;
		const neverLoaded = interstitial.assetList.length === 0 && !interstitial.assetListLoader;
		const playOnce = interstitial.cue.once;
		if (neverLoaded || !playOnce) {
			const player = this.preloadAssets(interstitial, assetListIndex);
			if (player != null && player.interstitial.appendInPlace) {
				const media = this.primaryMedia;
				if (media) this.bufferAssetPlayer(player, media);
			}
		}
	}
	preloadAssets(interstitial, assetListIndex) {
		const uri = interstitial.assetUrl;
		const assetListLength = interstitial.assetList.length;
		const neverLoaded = assetListLength === 0 && !interstitial.assetListLoader;
		const playOnce = interstitial.cue.once;
		if (neverLoaded) {
			const timelineStart = interstitial.timelineStart;
			if (interstitial.appendInPlace) {
				var _playingItem$nextEven;
				const playingItem = this.playingItem;
				if (!this.isInterstitial(playingItem) && (playingItem == null || (_playingItem$nextEven = playingItem.nextEvent) == null ? void 0 : _playingItem$nextEven.identifier) === interstitial.identifier) this.flushFrontBuffer(timelineStart + .25);
			}
			let hlsStartOffset;
			let liveStartPosition = 0;
			if (!this.playingItem && this.primaryLive) {
				liveStartPosition = this.hls.startPosition;
				if (liveStartPosition === -1) liveStartPosition = this.hls.liveSyncPosition || 0;
			}
			if (liveStartPosition && !(interstitial.cue.pre || interstitial.cue.post)) {
				const startOffset = liveStartPosition - timelineStart;
				if (startOffset > 0) hlsStartOffset = Math.round(startOffset * 1e3) / 1e3;
			}
			this.log(`Load interstitial asset ${assetListIndex + 1}/${uri ? 1 : assetListLength} ${interstitial}${hlsStartOffset ? ` live-start: ${liveStartPosition} start-offset: ${hlsStartOffset}` : ""}`);
			if (uri) return this.createAsset(interstitial, 0, 0, timelineStart, interstitial.duration, uri);
			const assetListLoader = this.assetListLoader.loadAssetList(interstitial, hlsStartOffset);
			if (assetListLoader) interstitial.assetListLoader = assetListLoader;
		} else if (!playOnce && assetListLength) {
			for (let i = assetListIndex; i < assetListLength; i++) {
				const _asset = interstitial.assetList[i];
				const playerIndex = this.getAssetPlayerQueueIndex(_asset.identifier);
				if ((playerIndex === -1 || this.playerQueue[playerIndex].destroyed) && !_asset.error) this.createAssetPlayer(interstitial, _asset, i);
			}
			const asset = interstitial.assetList[assetListIndex];
			if (asset) {
				const player = this.getAssetPlayer(asset.identifier);
				if (player) player.loadSource();
				return player;
			}
		}
		return null;
	}
	flushFrontBuffer(startOffset) {
		const requiredTracks = this.requiredTracks;
		if (!requiredTracks) return;
		this.log(`Removing front buffer starting at ${startOffset}`);
		Object.keys(requiredTracks).forEach((type) => {
			this.hls.trigger(Events.BUFFER_FLUSHING, {
				startOffset,
				endOffset: Infinity,
				type
			});
		});
	}
	getAssetPlayerQueueIndex(assetId) {
		const playerQueue = this.playerQueue;
		for (let i = 0; i < playerQueue.length; i++) if (assetId === playerQueue[i].assetId) return i;
		return -1;
	}
	getAssetPlayer(assetId) {
		const index = this.getAssetPlayerQueueIndex(assetId);
		return this.playerQueue[index] || null;
	}
	getBufferingPlayer() {
		const { playerQueue, primaryMedia } = this;
		if (primaryMedia) {
			for (let i = 0; i < playerQueue.length; i++) if (playerQueue[i].media === primaryMedia) return playerQueue[i];
		}
		return null;
	}
	createAsset(interstitial, assetListIndex, startOffset, timelineStart, duration, uri) {
		const assetItem = {
			parentIdentifier: interstitial.identifier,
			identifier: generateAssetIdentifier(interstitial, uri, assetListIndex),
			duration,
			startOffset,
			timelineStart,
			uri
		};
		return this.createAssetPlayer(interstitial, assetItem, assetListIndex);
	}
	createAssetPlayer(interstitial, assetItem, assetListIndex) {
		const primary = this.hls;
		const userConfig = primary.userConfig;
		let videoPreference = userConfig.videoPreference;
		const currentLevel = primary.loadLevelObj || primary.levels[primary.currentLevel];
		if (videoPreference || currentLevel) {
			videoPreference = _extends({}, videoPreference);
			if (currentLevel.videoCodec) videoPreference.videoCodec = currentLevel.videoCodec;
			if (currentLevel.videoRange) videoPreference.allowedVideoRanges = [currentLevel.videoRange];
		}
		const selectedAudio = primary.audioTracks[primary.audioTrack];
		const selectedSubtitle = primary.subtitleTracks[primary.subtitleTrack];
		let startPosition = 0;
		if (this.primaryLive || interstitial.appendInPlace) {
			const timePastStart = this.timelinePos - assetItem.timelineStart;
			if (timePastStart > 1) {
				const duration = assetItem.duration;
				if (duration && timePastStart < duration) startPosition = timePastStart;
			}
		}
		const assetId = assetItem.identifier;
		const playerConfig = _objectSpread2(_objectSpread2({}, userConfig), {}, {
			maxMaxBufferLength: Math.min(180, primary.config.maxMaxBufferLength),
			autoStartLoad: true,
			startFragPrefetch: true,
			primarySessionId: primary.sessionId,
			assetPlayerId: assetId,
			abrEwmaDefaultEstimate: primary.bandwidthEstimate,
			interstitialsController: void 0,
			startPosition,
			liveDurationInfinity: false,
			testBandwidth: false,
			videoPreference,
			audioPreference: selectedAudio || userConfig.audioPreference,
			subtitlePreference: selectedSubtitle || userConfig.subtitlePreference
		});
		if (interstitial.appendInPlace) {
			interstitial.appendInPlaceStarted = true;
			if (assetItem.timelineStart) playerConfig.timelineOffset = assetItem.timelineStart;
		}
		const cmcd = playerConfig.cmcd;
		if (cmcd != null && cmcd.sessionId && cmcd.contentId) playerConfig.cmcd = _extends({}, cmcd, { contentId: hash(assetItem.uri) });
		if (this.getAssetPlayer(assetId)) this.warn(`Duplicate date range identifier ${interstitial} and asset ${assetId}`);
		const player = new HlsAssetPlayer(this.HlsPlayerClass, playerConfig, interstitial, assetItem);
		this.playerQueue.push(player);
		interstitial.assetList[assetListIndex] = assetItem;
		let initialDuration = true;
		const updateAssetPlayerDetails = (details) => {
			if (details.live) {
				var _this$schedule9;
				const error = /* @__PURE__ */ new Error(`Interstitials MUST be VOD assets ${interstitial}`);
				const errorData = {
					fatal: true,
					type: ErrorTypes.OTHER_ERROR,
					details: ErrorDetails.INTERSTITIAL_ASSET_ITEM_ERROR,
					error
				};
				const scheduleIndex = ((_this$schedule9 = this.schedule) == null ? void 0 : _this$schedule9.findEventIndex(interstitial.identifier)) || -1;
				this.handleAssetItemError(errorData, interstitial, scheduleIndex, assetListIndex, error.message);
				return;
			}
			const duration = details.edge - details.fragmentStart;
			const currentAssetDuration = assetItem.duration;
			if (initialDuration || currentAssetDuration === null || duration > currentAssetDuration) {
				initialDuration = false;
				this.log(`Interstitial asset "${assetId}" duration change ${currentAssetDuration} > ${duration}`);
				assetItem.duration = duration;
				this.updateSchedule();
			}
		};
		player.on(Events.LEVEL_UPDATED, (event, { details }) => updateAssetPlayerDetails(details));
		player.on(Events.LEVEL_PTS_UPDATED, (event, { details }) => updateAssetPlayerDetails(details));
		player.on(Events.EVENT_CUE_ENTER, () => this.onInterstitialCueEnter());
		const onBufferCodecs = (event, data) => {
			const inQueuPlayer = this.getAssetPlayer(assetId);
			if (inQueuPlayer && data.tracks) {
				inQueuPlayer.off(Events.BUFFER_CODECS, onBufferCodecs);
				inQueuPlayer.tracks = data.tracks;
				const media = this.primaryMedia;
				if (this.bufferingAsset === inQueuPlayer.assetItem && media && !inQueuPlayer.media) this.bufferAssetPlayer(inQueuPlayer, media);
			}
		};
		player.on(Events.BUFFER_CODECS, onBufferCodecs);
		const bufferedToEnd = () => {
			var _this$schedule$items3;
			const inQueuPlayer = this.getAssetPlayer(assetId);
			this.log(`buffered to end of asset ${inQueuPlayer}`);
			if (!inQueuPlayer || !this.schedule) return;
			const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
			const item = (_this$schedule$items3 = this.schedule.items) == null ? void 0 : _this$schedule$items3[scheduleIndex];
			if (this.isInterstitial(item)) this.advanceAssetBuffering(item, assetItem);
		};
		player.on(Events.BUFFERED_TO_END, bufferedToEnd);
		const endedWithAssetIndex = (assetIndex) => {
			return () => {
				if (!this.getAssetPlayer(assetId) || !this.schedule) return;
				this.shouldPlay = true;
				const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
				this.advanceAfterAssetEnded(interstitial, scheduleIndex, assetIndex);
			};
		};
		player.once(Events.MEDIA_ENDED, endedWithAssetIndex(assetListIndex));
		player.once(Events.PLAYOUT_LIMIT_REACHED, endedWithAssetIndex(Infinity));
		player.on(Events.ERROR, (event, data) => {
			if (!this.schedule) return;
			const inQueuPlayer = this.getAssetPlayer(assetId);
			if (data.details === ErrorDetails.BUFFER_STALLED_ERROR) {
				if (inQueuPlayer != null && inQueuPlayer.appendInPlace) {
					this.handleInPlaceStall(interstitial);
					return;
				}
				this.onTimeupdate();
				this.checkBuffer(true);
				return;
			}
			this.handleAssetItemError(data, interstitial, this.schedule.findEventIndex(interstitial.identifier), assetListIndex, `Asset player error ${data.error} ${interstitial}`);
		});
		player.on(Events.DESTROYING, () => {
			if (!this.getAssetPlayer(assetId) || !this.schedule) return;
			const error = /* @__PURE__ */ new Error(`Asset player destroyed unexpectedly ${assetId}`);
			const errorData = {
				fatal: true,
				type: ErrorTypes.OTHER_ERROR,
				details: ErrorDetails.INTERSTITIAL_ASSET_ITEM_ERROR,
				error
			};
			this.handleAssetItemError(errorData, interstitial, this.schedule.findEventIndex(interstitial.identifier), assetListIndex, error.message);
		});
		this.log(`INTERSTITIAL_ASSET_PLAYER_CREATED ${eventAssetToString(assetItem)}`);
		this.hls.trigger(Events.INTERSTITIAL_ASSET_PLAYER_CREATED, {
			asset: assetItem,
			assetListIndex,
			event: interstitial,
			player
		});
		return player;
	}
	clearInterstitial(interstitial, toSegment) {
		this.clearAssetPlayers(interstitial, toSegment);
		interstitial.reset();
	}
	clearAssetPlayers(interstitial, toSegment) {
		interstitial.assetList.forEach((asset) => {
			this.clearAssetPlayer(asset.identifier, toSegment);
		});
	}
	resetAssetPlayer(assetId) {
		const playerIndex = this.getAssetPlayerQueueIndex(assetId);
		if (playerIndex !== -1) {
			this.log(`reset asset player "${assetId}" after error`);
			const player = this.playerQueue[playerIndex];
			this.transferMediaFromPlayer(player, null);
			player.resetDetails();
		}
	}
	clearAssetPlayer(assetId, toSegment) {
		const playerIndex = this.getAssetPlayerQueueIndex(assetId);
		if (playerIndex !== -1) {
			const player = this.playerQueue[playerIndex];
			this.log(`clear ${player} toSegment: ${toSegment ? segmentToString(toSegment) : toSegment}`);
			this.transferMediaFromPlayer(player, toSegment);
			this.playerQueue.splice(playerIndex, 1);
			player.destroy();
		}
	}
	emptyPlayerQueue() {
		let player;
		while (player = this.playerQueue.pop()) player.destroy();
		this.playerQueue = [];
	}
	startAssetPlayer(player, assetListIndex, scheduleItems, scheduleIndex, media) {
		const { interstitial, assetItem, assetId } = player;
		const assetListLength = interstitial.assetList.length;
		const playingAsset = this.playingAsset;
		this.endedAsset = null;
		this.playingAsset = assetItem;
		if (!playingAsset || playingAsset.identifier !== assetId) {
			if (playingAsset) {
				this.clearAssetPlayer(playingAsset.identifier, scheduleItems[scheduleIndex]);
				delete playingAsset.error;
			}
			this.log(`INTERSTITIAL_ASSET_STARTED ${assetListIndex + 1}/${assetListLength} ${eventAssetToString(assetItem)}`);
			this.hls.trigger(Events.INTERSTITIAL_ASSET_STARTED, {
				asset: assetItem,
				assetListIndex,
				event: interstitial,
				schedule: scheduleItems.slice(0),
				scheduleIndex,
				player
			});
		}
		this.bufferAssetPlayer(player, media);
	}
	bufferAssetPlayer(player, media) {
		var _this$schedule$items4, _this$detachedData5;
		if (!this.schedule) return;
		const { interstitial, assetItem } = player;
		const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
		const item = (_this$schedule$items4 = this.schedule.items) == null ? void 0 : _this$schedule$items4[scheduleIndex];
		if (!item) return;
		player.loadSource();
		this.setBufferingItem(item);
		this.bufferingAsset = assetItem;
		const bufferingPlayer = this.getBufferingPlayer();
		if (bufferingPlayer === player) return;
		const appendInPlaceNext = interstitial.appendInPlace;
		if (appendInPlaceNext && (bufferingPlayer == null ? void 0 : bufferingPlayer.interstitial.appendInPlace) === false) return;
		const activeTracks = (bufferingPlayer == null ? void 0 : bufferingPlayer.tracks) || ((_this$detachedData5 = this.detachedData) == null ? void 0 : _this$detachedData5.tracks) || this.requiredTracks;
		if (appendInPlaceNext && assetItem !== this.playingAsset) {
			if (!player.tracks) {
				this.log(`Waiting for track info before buffering ${player}`);
				return;
			}
			if (activeTracks && !isCompatibleTrackChange(activeTracks, player.tracks)) {
				const error = /* @__PURE__ */ new Error(`Asset ${eventAssetToString(assetItem)} SourceBuffer tracks ('${Object.keys(player.tracks)}') are not compatible with primary content tracks ('${Object.keys(activeTracks)}')`);
				const errorData = {
					fatal: true,
					type: ErrorTypes.OTHER_ERROR,
					details: ErrorDetails.INTERSTITIAL_ASSET_ITEM_ERROR,
					error
				};
				const assetListIndex = interstitial.findAssetIndex(assetItem);
				this.handleAssetItemError(errorData, interstitial, scheduleIndex, assetListIndex, error.message);
				return;
			}
		}
		this.transferMediaTo(player, media);
	}
	handleInPlaceStall(interstitial) {
		const schedule = this.schedule;
		const media = this.primaryMedia;
		if (!schedule || !media) return;
		const currentTime = media.currentTime;
		const foundAssetIndex = schedule.findAssetIndex(interstitial, currentTime);
		const stallingAsset = interstitial.assetList[foundAssetIndex];
		if (stallingAsset) {
			const player = this.getAssetPlayer(stallingAsset.identifier);
			if (player) {
				const assetCurrentTime = player.currentTime || currentTime - stallingAsset.timelineStart;
				const distanceFromEnd = player.duration - assetCurrentTime;
				this.warn(`Stalled at ${assetCurrentTime} of ${assetCurrentTime + distanceFromEnd} in ${player} ${interstitial} (media.currentTime: ${currentTime})`);
				if (assetCurrentTime && (distanceFromEnd / media.playbackRate < .5 || player.bufferedInPlaceToEnd(media)) && player.hls) {
					const scheduleIndex = schedule.findEventIndex(interstitial.identifier);
					this.advanceAfterAssetEnded(interstitial, scheduleIndex, foundAssetIndex);
				}
			}
		}
	}
	advanceInPlace(time) {
		const media = this.primaryMedia;
		if (media && media.currentTime < time) media.currentTime = time;
	}
	handleAssetItemError(data, interstitial, scheduleIndex, assetListIndex, errorMessage) {
		if (data.details === ErrorDetails.BUFFER_STALLED_ERROR) return;
		const assetItem = interstitial.assetList[assetListIndex] || null;
		this.warn(`INTERSTITIAL_ASSET_ERROR ${assetItem ? eventAssetToString(assetItem) : assetItem} ${data.error}`);
		if (!this.schedule) return;
		const assetId = (assetItem == null ? void 0 : assetItem.identifier) || "";
		const playerIndex = this.getAssetPlayerQueueIndex(assetId);
		const player = this.playerQueue[playerIndex] || null;
		const items = this.schedule.items;
		const interstitialAssetError = _extends({}, data, {
			fatal: false,
			errorAction: createDoNothingErrorAction(true),
			asset: assetItem,
			assetListIndex,
			event: interstitial,
			schedule: items,
			scheduleIndex,
			player
		});
		this.hls.trigger(Events.INTERSTITIAL_ASSET_ERROR, interstitialAssetError);
		if (!data.fatal) return;
		const playingAsset = this.playingAsset;
		const bufferingAsset = this.bufferingAsset;
		const error = new Error(errorMessage);
		if (assetItem) {
			this.clearAssetPlayer(assetId, null);
			assetItem.error = error;
		}
		if (!interstitial.assetList.some((asset) => !asset.error)) interstitial.error = error;
		else for (let i = assetListIndex; i < interstitial.assetList.length; i++) this.resetAssetPlayer(interstitial.assetList[i].identifier);
		this.updateSchedule(true);
		if (interstitial.error) this.primaryFallback(interstitial);
		else if (playingAsset && playingAsset.identifier === assetId) this.advanceAfterAssetEnded(interstitial, scheduleIndex, assetListIndex);
		else if (bufferingAsset && bufferingAsset.identifier === assetId && this.isInterstitial(this.bufferingItem)) this.advanceAssetBuffering(this.bufferingItem, bufferingAsset);
	}
	primaryFallback(interstitial) {
		const flushStart = interstitial.timelineStart;
		const playingItem = this.effectivePlayingItem;
		let timelinePos = this.timelinePos;
		if (playingItem) {
			this.log(`Fallback to primary from event "${interstitial.identifier}" start: ${flushStart} pos: ${timelinePos} playing: ${segmentToString(playingItem)} error: ${interstitial.error}`);
			if (timelinePos === -1) timelinePos = this.hls.startPosition;
			const newPlayingItem = this.updateItem(playingItem, timelinePos);
			if (this.itemsMatch(playingItem, newPlayingItem)) this.clearInterstitial(interstitial, null);
			if (interstitial.appendInPlace) {
				this.attachPrimary(flushStart, null);
				this.flushFrontBuffer(flushStart);
			}
		} else if (timelinePos === -1) {
			this.checkStart();
			return;
		}
		if (!this.schedule) return;
		const scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
		this.setSchedulePosition(scheduleIndex);
	}
	onAssetListLoaded(event, data) {
		var _this$schedule0, _this$bufferingItem2;
		const interstitial = data.event;
		const interstitialId = interstitial.identifier;
		const assets = data.assetListResponse.ASSETS;
		if (!((_this$schedule0 = this.schedule) != null && _this$schedule0.hasEvent(interstitialId))) return;
		const eventStart = interstitial.timelineStart;
		const previousDuration = interstitial.duration;
		let sumDuration = 0;
		assets.forEach((asset, assetListIndex) => {
			const duration = parseFloat(asset.DURATION);
			this.createAsset(interstitial, assetListIndex, sumDuration, eventStart + sumDuration, duration, asset.URI);
			sumDuration += duration;
		});
		interstitial.duration = sumDuration;
		this.log(`Loaded asset-list with duration: ${sumDuration} (was: ${previousDuration}) ${interstitial}`);
		const waitingItem = this.waitingItem;
		const waitingForItem = (waitingItem == null ? void 0 : waitingItem.event.identifier) === interstitialId;
		this.updateSchedule();
		const bufferingEvent = (_this$bufferingItem2 = this.bufferingItem) == null ? void 0 : _this$bufferingItem2.event;
		if (waitingForItem) {
			var _this$schedule$items5;
			const scheduleIndex = this.schedule.findEventIndex(interstitialId);
			const item = (_this$schedule$items5 = this.schedule.items) == null ? void 0 : _this$schedule$items5[scheduleIndex];
			if (item) {
				if (!this.playingItem && this.timelinePos > item.end) {
					if (this.schedule.findItemIndexAtTime(this.timelinePos) !== scheduleIndex) {
						interstitial.error = /* @__PURE__ */ new Error(`Interstitial ${assets.length ? "no longer within playback range" : "asset-list is empty"} ${this.timelinePos} ${interstitial}`);
						this.log(interstitial.error.message);
						this.updateSchedule(true);
						this.primaryFallback(interstitial);
						return;
					}
				}
				this.setBufferingItem(item);
			}
			this.setSchedulePosition(scheduleIndex);
		} else if ((bufferingEvent == null ? void 0 : bufferingEvent.identifier) === interstitialId) {
			const assetItem = interstitial.assetList[0];
			if (assetItem) {
				const player = this.getAssetPlayer(assetItem.identifier);
				if (bufferingEvent.appendInPlace) {
					const media = this.primaryMedia;
					if (player && media) this.bufferAssetPlayer(player, media);
				} else if (player) player.loadSource();
			}
		}
	}
	onError(event, data) {
		if (!this.schedule) return;
		switch (data.details) {
			case ErrorDetails.ASSET_LIST_PARSING_ERROR:
			case ErrorDetails.ASSET_LIST_LOAD_ERROR:
			case ErrorDetails.ASSET_LIST_LOAD_TIMEOUT: {
				const interstitial = data.interstitial;
				if (interstitial) {
					this.updateSchedule(true);
					this.primaryFallback(interstitial);
				}
				break;
			}
			case ErrorDetails.BUFFER_STALLED_ERROR: {
				const stallingItem = this.endedItem || this.waitingItem || this.playingItem;
				if (this.isInterstitial(stallingItem) && stallingItem.event.appendInPlace) {
					this.handleInPlaceStall(stallingItem.event);
					return;
				}
				this.log(`Primary player stall @${this.timelinePos} bufferedPos: ${this.bufferedPos}`);
				this.onTimeupdate();
				this.checkBuffer(true);
				break;
			}
		}
	}
};
var TICK_INTERVAL$2 = 500;
var SubtitleStreamController = class extends BaseStreamController {
	constructor(hls, fragmentTracker, keyLoader) {
		super(hls, fragmentTracker, keyLoader, "subtitle-stream-controller", PlaylistLevelType.SUBTITLE);
		this.currentTrackId = -1;
		this.tracksBuffered = [];
		this.mainDetails = null;
		this.registerListeners();
	}
	onHandlerDestroying() {
		this.unregisterListeners();
		super.onHandlerDestroying();
		this.mainDetails = null;
	}
	registerListeners() {
		super.registerListeners();
		const { hls } = this;
		hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.on(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
		hls.on(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
		hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
		hls.on(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this);
		hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
	}
	unregisterListeners() {
		super.unregisterListeners();
		const { hls } = this;
		hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.off(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
		hls.off(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
		hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
		hls.off(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this);
		hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
	}
	startLoad(startPosition, skipSeekToStartPosition) {
		this.stopLoad();
		this.state = State.IDLE;
		this.setInterval(TICK_INTERVAL$2);
		this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset;
		this.startPosition = skipSeekToStartPosition ? -1 : startPosition;
		this.tick();
	}
	onManifestLoading() {
		super.onManifestLoading();
		this.mainDetails = null;
	}
	onMediaDetaching(event, data) {
		this.tracksBuffered = [];
		super.onMediaDetaching(event, data);
	}
	onLevelLoaded(event, data) {
		this.mainDetails = data.details;
	}
	onSubtitleFragProcessed(event, data) {
		const { frag, success } = data;
		if (!this.fragContextChanged(frag)) {
			if (isMediaFragment(frag)) this.fragPrevious = frag;
			this.state = State.IDLE;
		}
		if (!success) return;
		const buffered = this.tracksBuffered[this.currentTrackId];
		if (!buffered) return;
		let timeRange;
		const fragStart = frag.start;
		for (let i = 0; i < buffered.length; i++) if (fragStart >= buffered[i].start && fragStart <= buffered[i].end) {
			timeRange = buffered[i];
			break;
		}
		const fragEnd = frag.start + frag.duration;
		if (timeRange) timeRange.end = fragEnd;
		else {
			timeRange = {
				start: fragStart,
				end: fragEnd
			};
			buffered.push(timeRange);
		}
		this.fragmentTracker.fragBuffered(frag);
		this.fragBufferedComplete(frag, null);
		if (this.media) this.tick();
	}
	onBufferFlushing(event, data) {
		const { startOffset, endOffset } = data;
		if (startOffset === 0 && endOffset !== Number.POSITIVE_INFINITY) {
			const endOffsetSubtitles = endOffset - 1;
			if (endOffsetSubtitles <= 0) return;
			data.endOffsetSubtitles = Math.max(0, endOffsetSubtitles);
			this.tracksBuffered.forEach((buffered) => {
				for (let i = 0; i < buffered.length;) {
					if (buffered[i].end <= endOffsetSubtitles) {
						buffered.shift();
						continue;
					} else if (buffered[i].start < endOffsetSubtitles) buffered[i].start = endOffsetSubtitles;
					else break;
					i++;
				}
			});
			this.fragmentTracker.removeFragmentsInRange(startOffset, endOffsetSubtitles, PlaylistLevelType.SUBTITLE);
		}
	}
	onError(event, data) {
		const frag = data.frag;
		if ((frag == null ? void 0 : frag.type) === PlaylistLevelType.SUBTITLE) {
			if (data.details === ErrorDetails.FRAG_GAP) this.fragmentTracker.fragBuffered(frag, true);
			if (this.fragCurrent) this.fragCurrent.abortRequests();
			if (this.state !== State.STOPPED) this.state = State.IDLE;
		}
	}
	onSubtitleTracksUpdated(event, { subtitleTracks }) {
		if (this.levels && subtitleOptionsIdentical(this.levels, subtitleTracks)) {
			this.levels = subtitleTracks.map((mediaPlaylist) => new Level(mediaPlaylist));
			return;
		}
		this.tracksBuffered = [];
		this.levels = subtitleTracks.map((mediaPlaylist) => {
			const level = new Level(mediaPlaylist);
			this.tracksBuffered[level.id] = [];
			return level;
		});
		this.fragmentTracker.removeFragmentsInRange(0, Number.POSITIVE_INFINITY, PlaylistLevelType.SUBTITLE);
		this.fragPrevious = null;
		this.mediaBuffer = null;
	}
	onSubtitleTrackSwitch(event, data) {
		var _this$levels;
		this.currentTrackId = data.id;
		if (!((_this$levels = this.levels) != null && _this$levels.length) || this.currentTrackId === -1) {
			this.clearInterval();
			return;
		}
		const currentTrack = this.levels[this.currentTrackId];
		if (currentTrack != null && currentTrack.details) this.mediaBuffer = this.mediaBufferTimeRanges;
		else this.mediaBuffer = null;
		if (currentTrack && this.state !== State.STOPPED) this.setInterval(TICK_INTERVAL$2);
	}
	onSubtitleTrackLoaded(event, data) {
		var _track$details;
		const { currentTrackId, levels } = this;
		const { details: newDetails, id: trackId } = data;
		if (!levels) {
			this.warn(`Subtitle tracks were reset while loading level ${trackId}`);
			return;
		}
		const track = levels[trackId];
		if (trackId >= levels.length || !track) return;
		this.log(`Subtitle track ${trackId} loaded [${newDetails.startSN},${newDetails.endSN}]${newDetails.lastPartSn ? `[part-${newDetails.lastPartSn}-${newDetails.lastPartIndex}]` : ""},duration:${newDetails.totalduration}`);
		this.mediaBuffer = this.mediaBufferTimeRanges;
		let sliding = 0;
		if (newDetails.live || (_track$details = track.details) != null && _track$details.live) {
			if (newDetails.deltaUpdateFailed) return;
			const mainDetails = this.mainDetails;
			if (!mainDetails) {
				this.startFragRequested = false;
				return;
			}
			const mainSlidingStartFragment = mainDetails.fragments[0];
			if (!track.details) {
				if (newDetails.hasProgramDateTime && mainDetails.hasProgramDateTime) {
					alignMediaPlaylistByPDT(newDetails, mainDetails);
					sliding = newDetails.fragmentStart;
				} else if (mainSlidingStartFragment) {
					sliding = mainSlidingStartFragment.start;
					addSliding(newDetails, sliding);
				}
			} else {
				var _this$levelLastLoaded;
				sliding = this.alignPlaylists(newDetails, track.details, (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details);
				if (sliding === 0 && mainSlidingStartFragment) {
					sliding = mainSlidingStartFragment.start;
					addSliding(newDetails, sliding);
				}
			}
			if (mainDetails && !this.startFragRequested) this.setStartPosition(mainDetails, sliding);
		}
		track.details = newDetails;
		this.levelLastLoaded = track;
		if (trackId !== currentTrackId) return;
		this.hls.trigger(Events.SUBTITLE_TRACK_UPDATED, {
			details: newDetails,
			id: trackId,
			groupId: data.groupId
		});
		this.tick();
		if (newDetails.live && !this.fragCurrent && this.media && this.state === State.IDLE) {
			if (!findFragmentByPTS(null, newDetails.fragments, this.media.currentTime, 0)) {
				this.warn("Subtitle playlist not aligned with playback");
				track.details = void 0;
			}
		}
	}
	_handleFragmentLoadComplete(fragLoadedData) {
		const { frag, payload } = fragLoadedData;
		const decryptData = frag.decryptdata;
		const hls = this.hls;
		if (this.fragContextChanged(frag)) return;
		if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
			const startTime = performance.now();
			this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch((err) => {
				hls.trigger(Events.ERROR, {
					type: ErrorTypes.MEDIA_ERROR,
					details: ErrorDetails.FRAG_DECRYPT_ERROR,
					fatal: false,
					error: err,
					reason: err.message,
					frag
				});
				throw err;
			}).then((decryptedData) => {
				const endTime = performance.now();
				hls.trigger(Events.FRAG_DECRYPTED, {
					frag,
					payload: decryptedData,
					stats: {
						tstart: startTime,
						tdecrypt: endTime
					}
				});
			}).catch((err) => {
				this.warn(`${err.name}: ${err.message}`);
				this.state = State.IDLE;
			});
		}
	}
	doTick() {
		if (!this.media) {
			this.state = State.IDLE;
			return;
		}
		if (this.state === State.IDLE) {
			const { currentTrackId, levels } = this;
			const track = levels == null ? void 0 : levels[currentTrackId];
			if (!track || !levels.length || !track.details) return;
			if (this.waitForLive(track)) return;
			const { config } = this;
			const currentTime = this.getLoadPosition();
			const { end: targetBufferTime, len: bufferLen } = BufferHelper.bufferedInfo(this.tracksBuffered[this.currentTrackId] || [], currentTime, config.maxBufferHole);
			const trackDetails = track.details;
			if (bufferLen > this.hls.maxBufferLength + trackDetails.levelTargetDuration) return;
			const fragments = trackDetails.fragments;
			const fragLen = fragments.length;
			const end = trackDetails.edge;
			let foundFrag = null;
			const fragPrevious = this.fragPrevious;
			if (targetBufferTime < end) {
				const tolerance = config.maxFragLookUpTolerance;
				const lookupTolerance = targetBufferTime > end - tolerance ? 0 : tolerance;
				foundFrag = findFragmentByPTS(fragPrevious, fragments, Math.max(fragments[0].start, targetBufferTime), lookupTolerance);
				if (!foundFrag && fragPrevious && fragPrevious.start < fragments[0].start) foundFrag = fragments[0];
			} else foundFrag = fragments[fragLen - 1];
			foundFrag = this.filterReplacedPrimary(foundFrag, track.details);
			if (!foundFrag) return;
			const prevFrag = fragments[foundFrag.sn - trackDetails.startSN - 1];
			if (prevFrag && prevFrag.cc === foundFrag.cc && this.fragmentTracker.getState(prevFrag) === FragmentState.NOT_LOADED) foundFrag = prevFrag;
			if (this.fragmentTracker.getState(foundFrag) === FragmentState.NOT_LOADED) {
				const fragToLoad = this.mapToInitFragWhenRequired(foundFrag);
				if (fragToLoad) this.loadFragment(fragToLoad, track, targetBufferTime);
			}
		}
	}
	loadFragment(frag, level, targetBufferTime) {
		if (!isMediaFragment(frag)) this._loadInitSegment(frag, level);
		else super.loadFragment(frag, level, targetBufferTime);
	}
	get mediaBufferTimeRanges() {
		return new BufferableInstance(this.tracksBuffered[this.currentTrackId] || []);
	}
};
var BufferableInstance = class {
	constructor(timeranges) {
		this.buffered = void 0;
		const getRange = (name, index, length) => {
			index = index >>> 0;
			if (index > length - 1) throw new DOMException(`Failed to execute '${name}' on 'TimeRanges': The index provided (${index}) is greater than the maximum bound (${length})`);
			return timeranges[index][name];
		};
		this.buffered = {
			get length() {
				return timeranges.length;
			},
			end(index) {
				return getRange("end", index, timeranges.length);
			},
			start(index) {
				return getRange("start", index, timeranges.length);
			}
		};
	}
};
/**
*
* This code was ported from the dash.js project at:
*   https://github.com/Dash-Industry-Forum/dash.js/blob/development/externals/cea608-parser.js
*   https://github.com/Dash-Industry-Forum/dash.js/commit/8269b26a761e0853bb21d78780ed945144ecdd4d#diff-71bc295a2d6b6b7093a1d3290d53a4b2
*
* The original copyright appears below:
*
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2015-2016, DASH Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*  1. Redistributions of source code must retain the above copyright notice, this
*  list of conditions and the following disclaimer.
*  * Redistributions in binary form must reproduce the above copyright notice,
*  this list of conditions and the following disclaimer in the documentation and/or
*  other materials provided with the distribution.
*  2. Neither the name of Dash Industry Forum nor the names of its
*  contributors may be used to endorse or promote products derived from this software
*  without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
*  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
*  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*/
/**
*  Exceptions from regular ASCII. CodePoints are mapped to UTF-16 codes
*/
var specialCea608CharsCodes = {
	42: 225,
	92: 233,
	94: 237,
	95: 243,
	96: 250,
	123: 231,
	124: 247,
	125: 209,
	126: 241,
	127: 9608,
	128: 174,
	129: 176,
	130: 189,
	131: 191,
	132: 8482,
	133: 162,
	134: 163,
	135: 9834,
	136: 224,
	137: 32,
	138: 232,
	139: 226,
	140: 234,
	141: 238,
	142: 244,
	143: 251,
	144: 193,
	145: 201,
	146: 211,
	147: 218,
	148: 220,
	149: 252,
	150: 8216,
	151: 161,
	152: 42,
	153: 8217,
	154: 9473,
	155: 169,
	156: 8480,
	157: 8226,
	158: 8220,
	159: 8221,
	160: 192,
	161: 194,
	162: 199,
	163: 200,
	164: 202,
	165: 203,
	166: 235,
	167: 206,
	168: 207,
	169: 239,
	170: 212,
	171: 217,
	172: 249,
	173: 219,
	174: 171,
	175: 187,
	176: 195,
	177: 227,
	178: 205,
	179: 204,
	180: 236,
	181: 210,
	182: 242,
	183: 213,
	184: 245,
	185: 123,
	186: 125,
	187: 92,
	188: 94,
	189: 95,
	190: 124,
	191: 8764,
	192: 196,
	193: 228,
	194: 214,
	195: 246,
	196: 223,
	197: 165,
	198: 164,
	199: 9475,
	200: 197,
	201: 229,
	202: 216,
	203: 248,
	204: 9487,
	205: 9491,
	206: 9495,
	207: 9499
};
/**
* Utils
*/
var getCharForByte = (byte) => String.fromCharCode(specialCea608CharsCodes[byte] || byte);
var NR_ROWS = 15;
var NR_COLS = 100;
var rowsLowCh1 = {
	17: 1,
	18: 3,
	21: 5,
	22: 7,
	23: 9,
	16: 11,
	19: 12,
	20: 14
};
var rowsHighCh1 = {
	17: 2,
	18: 4,
	21: 6,
	22: 8,
	23: 10,
	19: 13,
	20: 15
};
var rowsLowCh2 = {
	25: 1,
	26: 3,
	29: 5,
	30: 7,
	31: 9,
	24: 11,
	27: 12,
	28: 14
};
var rowsHighCh2 = {
	25: 2,
	26: 4,
	29: 6,
	30: 8,
	31: 10,
	27: 13,
	28: 15
};
var backgroundColors = [
	"white",
	"green",
	"blue",
	"cyan",
	"red",
	"yellow",
	"magenta",
	"black",
	"transparent"
];
var CaptionsLogger = class {
	constructor() {
		this.time = null;
		this.verboseLevel = 0;
	}
	log(severity, msg) {
		if (this.verboseLevel >= severity) {
			const m = typeof msg === "function" ? msg() : msg;
			logger.log(`${this.time} [${severity}] ${m}`);
		}
	}
};
var numArrayToHexArray = function numArrayToHexArray(numArray) {
	const hexArray = [];
	for (let j = 0; j < numArray.length; j++) hexArray.push(numArray[j].toString(16));
	return hexArray;
};
var PenState = class {
	constructor() {
		this.foreground = "white";
		this.underline = false;
		this.italics = false;
		this.background = "black";
		this.flash = false;
	}
	reset() {
		this.foreground = "white";
		this.underline = false;
		this.italics = false;
		this.background = "black";
		this.flash = false;
	}
	setStyles(styles) {
		const attribs = [
			"foreground",
			"underline",
			"italics",
			"background",
			"flash"
		];
		for (let i = 0; i < attribs.length; i++) {
			const style = attribs[i];
			if (styles.hasOwnProperty(style)) this[style] = styles[style];
		}
	}
	isDefault() {
		return this.foreground === "white" && !this.underline && !this.italics && this.background === "black" && !this.flash;
	}
	equals(other) {
		return this.foreground === other.foreground && this.underline === other.underline && this.italics === other.italics && this.background === other.background && this.flash === other.flash;
	}
	copy(newPenState) {
		this.foreground = newPenState.foreground;
		this.underline = newPenState.underline;
		this.italics = newPenState.italics;
		this.background = newPenState.background;
		this.flash = newPenState.flash;
	}
	toString() {
		return "color=" + this.foreground + ", underline=" + this.underline + ", italics=" + this.italics + ", background=" + this.background + ", flash=" + this.flash;
	}
};
/**
* Unicode character with styling and background.
* @constructor
*/
var StyledUnicodeChar = class {
	constructor() {
		this.uchar = " ";
		this.penState = new PenState();
	}
	reset() {
		this.uchar = " ";
		this.penState.reset();
	}
	setChar(uchar, newPenState) {
		this.uchar = uchar;
		this.penState.copy(newPenState);
	}
	setPenState(newPenState) {
		this.penState.copy(newPenState);
	}
	equals(other) {
		return this.uchar === other.uchar && this.penState.equals(other.penState);
	}
	copy(newChar) {
		this.uchar = newChar.uchar;
		this.penState.copy(newChar.penState);
	}
	isEmpty() {
		return this.uchar === " " && this.penState.isDefault();
	}
};
/**
* CEA-608 row consisting of NR_COLS instances of StyledUnicodeChar.
* @constructor
*/
var Row = class {
	constructor(logger) {
		this.chars = [];
		this.pos = 0;
		this.currPenState = new PenState();
		this.cueStartTime = null;
		this.logger = void 0;
		for (let i = 0; i < NR_COLS; i++) this.chars.push(new StyledUnicodeChar());
		this.logger = logger;
	}
	equals(other) {
		for (let i = 0; i < NR_COLS; i++) if (!this.chars[i].equals(other.chars[i])) return false;
		return true;
	}
	copy(other) {
		for (let i = 0; i < NR_COLS; i++) this.chars[i].copy(other.chars[i]);
	}
	isEmpty() {
		let empty = true;
		for (let i = 0; i < NR_COLS; i++) if (!this.chars[i].isEmpty()) {
			empty = false;
			break;
		}
		return empty;
	}
	/**
	*  Set the cursor to a valid column.
	*/
	setCursor(absPos) {
		if (this.pos !== absPos) this.pos = absPos;
		if (this.pos < 0) {
			this.logger.log(3, "Negative cursor position " + this.pos);
			this.pos = 0;
		} else if (this.pos > NR_COLS) {
			this.logger.log(3, "Too large cursor position " + this.pos);
			this.pos = NR_COLS;
		}
	}
	/**
	* Move the cursor relative to current position.
	*/
	moveCursor(relPos) {
		const newPos = this.pos + relPos;
		if (relPos > 1) for (let i = this.pos + 1; i < newPos + 1; i++) this.chars[i].setPenState(this.currPenState);
		this.setCursor(newPos);
	}
	/**
	* Backspace, move one step back and clear character.
	*/
	backSpace() {
		this.moveCursor(-1);
		this.chars[this.pos].setChar(" ", this.currPenState);
	}
	insertChar(byte) {
		if (byte >= 144) this.backSpace();
		const char = getCharForByte(byte);
		if (this.pos >= NR_COLS) {
			this.logger.log(0, () => "Cannot insert " + byte.toString(16) + " (" + char + ") at position " + this.pos + ". Skipping it!");
			return;
		}
		this.chars[this.pos].setChar(char, this.currPenState);
		this.moveCursor(1);
	}
	clearFromPos(startPos) {
		let i;
		for (i = startPos; i < NR_COLS; i++) this.chars[i].reset();
	}
	clear() {
		this.clearFromPos(0);
		this.pos = 0;
		this.currPenState.reset();
	}
	clearToEndOfRow() {
		this.clearFromPos(this.pos);
	}
	getTextString() {
		const chars = [];
		let empty = true;
		for (let i = 0; i < NR_COLS; i++) {
			const char = this.chars[i].uchar;
			if (char !== " ") empty = false;
			chars.push(char);
		}
		if (empty) return "";
		else return chars.join("");
	}
	setPenStyles(styles) {
		this.currPenState.setStyles(styles);
		this.chars[this.pos].setPenState(this.currPenState);
	}
};
/**
* Keep a CEA-608 screen of 32x15 styled characters
* @constructor
*/
var CaptionScreen = class {
	constructor(logger) {
		this.rows = [];
		this.currRow = NR_ROWS - 1;
		this.nrRollUpRows = null;
		this.lastOutputScreen = null;
		this.logger = void 0;
		for (let i = 0; i < NR_ROWS; i++) this.rows.push(new Row(logger));
		this.logger = logger;
	}
	reset() {
		for (let i = 0; i < NR_ROWS; i++) this.rows[i].clear();
		this.currRow = NR_ROWS - 1;
	}
	equals(other) {
		let equal = true;
		for (let i = 0; i < NR_ROWS; i++) if (!this.rows[i].equals(other.rows[i])) {
			equal = false;
			break;
		}
		return equal;
	}
	copy(other) {
		for (let i = 0; i < NR_ROWS; i++) this.rows[i].copy(other.rows[i]);
	}
	isEmpty() {
		let empty = true;
		for (let i = 0; i < NR_ROWS; i++) if (!this.rows[i].isEmpty()) {
			empty = false;
			break;
		}
		return empty;
	}
	backSpace() {
		this.rows[this.currRow].backSpace();
	}
	clearToEndOfRow() {
		this.rows[this.currRow].clearToEndOfRow();
	}
	/**
	* Insert a character (without styling) in the current row.
	*/
	insertChar(char) {
		this.rows[this.currRow].insertChar(char);
	}
	setPen(styles) {
		this.rows[this.currRow].setPenStyles(styles);
	}
	moveCursor(relPos) {
		this.rows[this.currRow].moveCursor(relPos);
	}
	setCursor(absPos) {
		this.logger.log(2, "setCursor: " + absPos);
		this.rows[this.currRow].setCursor(absPos);
	}
	setPAC(pacData) {
		this.logger.log(2, () => "pacData = " + stringify(pacData));
		let newRow = pacData.row - 1;
		if (this.nrRollUpRows && newRow < this.nrRollUpRows - 1) newRow = this.nrRollUpRows - 1;
		if (this.nrRollUpRows && this.currRow !== newRow) {
			for (let i = 0; i < NR_ROWS; i++) this.rows[i].clear();
			const topRowIndex = this.currRow + 1 - this.nrRollUpRows;
			const lastOutputScreen = this.lastOutputScreen;
			if (lastOutputScreen) {
				const prevLineTime = lastOutputScreen.rows[topRowIndex].cueStartTime;
				const time = this.logger.time;
				if (prevLineTime !== null && time !== null && prevLineTime < time) for (let i = 0; i < this.nrRollUpRows; i++) this.rows[newRow - this.nrRollUpRows + i + 1].copy(lastOutputScreen.rows[topRowIndex + i]);
			}
		}
		this.currRow = newRow;
		const row = this.rows[this.currRow];
		if (pacData.indent !== null) {
			const indent = pacData.indent;
			const prevPos = Math.max(indent - 1, 0);
			row.setCursor(pacData.indent);
			pacData.color = row.chars[prevPos].penState.foreground;
		}
		const styles = {
			foreground: pacData.color,
			underline: pacData.underline,
			italics: pacData.italics,
			background: "black",
			flash: false
		};
		this.setPen(styles);
	}
	/**
	* Set background/extra foreground, but first do back_space, and then insert space (backwards compatibility).
	*/
	setBkgData(bkgData) {
		this.logger.log(2, () => "bkgData = " + stringify(bkgData));
		this.backSpace();
		this.setPen(bkgData);
		this.insertChar(32);
	}
	setRollUpRows(nrRows) {
		this.nrRollUpRows = nrRows;
	}
	rollUp() {
		if (this.nrRollUpRows === null) {
			this.logger.log(3, "roll_up but nrRollUpRows not set yet");
			return;
		}
		this.logger.log(1, () => this.getDisplayText());
		const topRowIndex = this.currRow + 1 - this.nrRollUpRows;
		const topRow = this.rows.splice(topRowIndex, 1)[0];
		topRow.clear();
		this.rows.splice(this.currRow, 0, topRow);
		this.logger.log(2, "Rolling up");
	}
	/**
	* Get all non-empty rows with as unicode text.
	*/
	getDisplayText(asOneRow) {
		asOneRow = asOneRow || false;
		const displayText = [];
		let text = "";
		let rowNr = -1;
		for (let i = 0; i < NR_ROWS; i++) {
			const rowText = this.rows[i].getTextString();
			if (rowText) {
				rowNr = i + 1;
				if (asOneRow) displayText.push("Row " + rowNr + ": '" + rowText + "'");
				else displayText.push(rowText.trim());
			}
		}
		if (displayText.length > 0) if (asOneRow) text = "[" + displayText.join(" | ") + "]";
		else text = displayText.join("\n");
		return text;
	}
	getTextAndFormat() {
		return this.rows;
	}
};
var Cea608Channel = class {
	constructor(channelNumber, outputFilter, logger) {
		this.chNr = void 0;
		this.outputFilter = void 0;
		this.mode = void 0;
		this.verbose = void 0;
		this.displayedMemory = void 0;
		this.nonDisplayedMemory = void 0;
		this.lastOutputScreen = void 0;
		this.currRollUpRow = void 0;
		this.writeScreen = void 0;
		this.cueStartTime = void 0;
		this.logger = void 0;
		this.chNr = channelNumber;
		this.outputFilter = outputFilter;
		this.mode = null;
		this.verbose = 0;
		this.displayedMemory = new CaptionScreen(logger);
		this.nonDisplayedMemory = new CaptionScreen(logger);
		this.lastOutputScreen = new CaptionScreen(logger);
		this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
		this.writeScreen = this.displayedMemory;
		this.mode = null;
		this.cueStartTime = null;
		this.logger = logger;
	}
	reset() {
		this.mode = null;
		this.displayedMemory.reset();
		this.nonDisplayedMemory.reset();
		this.lastOutputScreen.reset();
		this.outputFilter.reset();
		this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
		this.writeScreen = this.displayedMemory;
		this.mode = null;
		this.cueStartTime = null;
	}
	getHandler() {
		return this.outputFilter;
	}
	setHandler(newHandler) {
		this.outputFilter = newHandler;
	}
	setPAC(pacData) {
		this.writeScreen.setPAC(pacData);
	}
	setBkgData(bkgData) {
		this.writeScreen.setBkgData(bkgData);
	}
	setMode(newMode) {
		if (newMode === this.mode) return;
		this.mode = newMode;
		this.logger.log(2, () => "MODE=" + newMode);
		if (this.mode === "MODE_POP-ON") this.writeScreen = this.nonDisplayedMemory;
		else {
			this.writeScreen = this.displayedMemory;
			this.writeScreen.reset();
		}
		if (this.mode !== "MODE_ROLL-UP") {
			this.displayedMemory.nrRollUpRows = null;
			this.nonDisplayedMemory.nrRollUpRows = null;
		}
		this.mode = newMode;
	}
	insertChars(chars) {
		for (let i = 0; i < chars.length; i++) this.writeScreen.insertChar(chars[i]);
		const screen = this.writeScreen === this.displayedMemory ? "DISP" : "NON_DISP";
		this.logger.log(2, () => screen + ": " + this.writeScreen.getDisplayText(true));
		if (this.mode === "MODE_PAINT-ON" || this.mode === "MODE_ROLL-UP") {
			this.logger.log(1, () => "DISPLAYED: " + this.displayedMemory.getDisplayText(true));
			this.outputDataUpdate();
		}
	}
	ccRCL() {
		this.logger.log(2, "RCL - Resume Caption Loading");
		this.setMode("MODE_POP-ON");
	}
	ccBS() {
		this.logger.log(2, "BS - BackSpace");
		if (this.mode === "MODE_TEXT") return;
		this.writeScreen.backSpace();
		if (this.writeScreen === this.displayedMemory) this.outputDataUpdate();
	}
	ccAOF() {}
	ccAON() {}
	ccDER() {
		this.logger.log(2, "DER- Delete to End of Row");
		this.writeScreen.clearToEndOfRow();
		this.outputDataUpdate();
	}
	ccRU(nrRows) {
		this.logger.log(2, "RU(" + nrRows + ") - Roll Up");
		this.writeScreen = this.displayedMemory;
		this.setMode("MODE_ROLL-UP");
		this.writeScreen.setRollUpRows(nrRows);
	}
	ccFON() {
		this.logger.log(2, "FON - Flash On");
		this.writeScreen.setPen({ flash: true });
	}
	ccRDC() {
		this.logger.log(2, "RDC - Resume Direct Captioning");
		this.setMode("MODE_PAINT-ON");
	}
	ccTR() {
		this.logger.log(2, "TR");
		this.setMode("MODE_TEXT");
	}
	ccRTD() {
		this.logger.log(2, "RTD");
		this.setMode("MODE_TEXT");
	}
	ccEDM() {
		this.logger.log(2, "EDM - Erase Displayed Memory");
		this.displayedMemory.reset();
		this.outputDataUpdate(true);
	}
	ccCR() {
		this.logger.log(2, "CR - Carriage Return");
		this.writeScreen.rollUp();
		this.outputDataUpdate(true);
	}
	ccENM() {
		this.logger.log(2, "ENM - Erase Non-displayed Memory");
		this.nonDisplayedMemory.reset();
	}
	ccEOC() {
		this.logger.log(2, "EOC - End Of Caption");
		if (this.mode === "MODE_POP-ON") {
			const tmp = this.displayedMemory;
			this.displayedMemory = this.nonDisplayedMemory;
			this.nonDisplayedMemory = tmp;
			this.writeScreen = this.nonDisplayedMemory;
			this.logger.log(1, () => "DISP: " + this.displayedMemory.getDisplayText());
		}
		this.outputDataUpdate(true);
	}
	ccTO(nrCols) {
		this.logger.log(2, "TO(" + nrCols + ") - Tab Offset");
		this.writeScreen.moveCursor(nrCols);
	}
	ccMIDROW(secondByte) {
		const styles = { flash: false };
		styles.underline = secondByte % 2 === 1;
		styles.italics = secondByte >= 46;
		if (!styles.italics) styles.foreground = [
			"white",
			"green",
			"blue",
			"cyan",
			"red",
			"yellow",
			"magenta"
		][Math.floor(secondByte / 2) - 16];
		else styles.foreground = "white";
		this.logger.log(2, "MIDROW: " + stringify(styles));
		this.writeScreen.setPen(styles);
	}
	outputDataUpdate(dispatch = false) {
		const time = this.logger.time;
		if (time === null) return;
		if (this.outputFilter) {
			if (this.cueStartTime === null && !this.displayedMemory.isEmpty()) this.cueStartTime = time;
			else if (!this.displayedMemory.equals(this.lastOutputScreen)) {
				this.outputFilter.newCue(this.cueStartTime, time, this.lastOutputScreen);
				if (dispatch && this.outputFilter.dispatchCue) this.outputFilter.dispatchCue();
				this.cueStartTime = this.displayedMemory.isEmpty() ? null : time;
			}
			this.lastOutputScreen.copy(this.displayedMemory);
		}
	}
	cueSplitAtTime(t) {
		if (this.outputFilter) {
			if (!this.displayedMemory.isEmpty()) {
				if (this.outputFilter.newCue) this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory);
				this.cueStartTime = t;
			}
		}
	}
};
var Cea608Parser = class {
	constructor(field, out1, out2) {
		this.channels = void 0;
		this.currentChannel = 0;
		this.cmdHistory = createCmdHistory();
		this.logger = void 0;
		const logger = this.logger = new CaptionsLogger();
		this.channels = [
			null,
			new Cea608Channel(field, out1, logger),
			new Cea608Channel(field + 1, out2, logger)
		];
	}
	getHandler(channel) {
		return this.channels[channel].getHandler();
	}
	setHandler(channel, newHandler) {
		this.channels[channel].setHandler(newHandler);
	}
	/**
	* Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs.
	*/
	addData(time, byteList) {
		this.logger.time = time;
		for (let i = 0; i < byteList.length; i += 2) {
			const a = byteList[i] & 127;
			const b = byteList[i + 1] & 127;
			let cmdFound = false;
			let charsFound = null;
			if (a === 0 && b === 0) continue;
			else this.logger.log(3, () => "[" + numArrayToHexArray([byteList[i], byteList[i + 1]]) + "] -> (" + numArrayToHexArray([a, b]) + ")");
			const cmdHistory = this.cmdHistory;
			if (a >= 16 && a <= 31) {
				if (hasCmdRepeated(a, b, cmdHistory)) {
					setLastCmd(null, null, cmdHistory);
					this.logger.log(3, () => "Repeated command (" + numArrayToHexArray([a, b]) + ") is dropped");
					continue;
				}
				setLastCmd(a, b, this.cmdHistory);
				cmdFound = this.parseCmd(a, b);
				if (!cmdFound) cmdFound = this.parseMidrow(a, b);
				if (!cmdFound) cmdFound = this.parsePAC(a, b);
				if (!cmdFound) cmdFound = this.parseBackgroundAttributes(a, b);
			} else setLastCmd(null, null, cmdHistory);
			if (!cmdFound) {
				charsFound = this.parseChars(a, b);
				if (charsFound) {
					const currChNr = this.currentChannel;
					if (currChNr && currChNr > 0) this.channels[currChNr].insertChars(charsFound);
					else this.logger.log(2, "No channel found yet. TEXT-MODE?");
				}
			}
			if (!cmdFound && !charsFound) this.logger.log(2, () => "Couldn't parse cleaned data " + numArrayToHexArray([a, b]) + " orig: " + numArrayToHexArray([byteList[i], byteList[i + 1]]));
		}
	}
	/**
	* Parse Command.
	* @returns True if a command was found
	*/
	parseCmd(a, b) {
		if (!((a === 20 || a === 28 || a === 21 || a === 29) && b >= 32 && b <= 47 || (a === 23 || a === 31) && b >= 33 && b <= 35)) return false;
		const chNr = a === 20 || a === 21 || a === 23 ? 1 : 2;
		const channel = this.channels[chNr];
		if (a === 20 || a === 21 || a === 28 || a === 29) {
			if (b === 32) channel.ccRCL();
			else if (b === 33) channel.ccBS();
			else if (b === 34) channel.ccAOF();
			else if (b === 35) channel.ccAON();
			else if (b === 36) channel.ccDER();
			else if (b === 37) channel.ccRU(2);
			else if (b === 38) channel.ccRU(3);
			else if (b === 39) channel.ccRU(4);
			else if (b === 40) channel.ccFON();
			else if (b === 41) channel.ccRDC();
			else if (b === 42) channel.ccTR();
			else if (b === 43) channel.ccRTD();
			else if (b === 44) channel.ccEDM();
			else if (b === 45) channel.ccCR();
			else if (b === 46) channel.ccENM();
			else if (b === 47) channel.ccEOC();
		} else channel.ccTO(b - 32);
		this.currentChannel = chNr;
		return true;
	}
	/**
	* Parse midrow styling command
	*/
	parseMidrow(a, b) {
		let chNr = 0;
		if ((a === 17 || a === 25) && b >= 32 && b <= 47) {
			if (a === 17) chNr = 1;
			else chNr = 2;
			if (chNr !== this.currentChannel) {
				this.logger.log(0, "Mismatch channel in midrow parsing");
				return false;
			}
			const channel = this.channels[chNr];
			if (!channel) return false;
			channel.ccMIDROW(b);
			this.logger.log(3, () => "MIDROW (" + numArrayToHexArray([a, b]) + ")");
			return true;
		}
		return false;
	}
	/**
	* Parse Preable Access Codes (Table 53).
	* @returns {Boolean} Tells if PAC found
	*/
	parsePAC(a, b) {
		let row;
		if (!((a >= 17 && a <= 23 || a >= 25 && a <= 31) && b >= 64 && b <= 127 || (a === 16 || a === 24) && b >= 64 && b <= 95)) return false;
		const chNr = a <= 23 ? 1 : 2;
		if (b >= 64 && b <= 95) row = chNr === 1 ? rowsLowCh1[a] : rowsLowCh2[a];
		else row = chNr === 1 ? rowsHighCh1[a] : rowsHighCh2[a];
		const channel = this.channels[chNr];
		if (!channel) return false;
		channel.setPAC(this.interpretPAC(row, b));
		this.currentChannel = chNr;
		return true;
	}
	/**
	* Interpret the second byte of the pac, and return the information.
	* @returns pacData with style parameters
	*/
	interpretPAC(row, byte) {
		let pacIndex;
		const pacData = {
			color: null,
			italics: false,
			indent: null,
			underline: false,
			row
		};
		if (byte > 95) pacIndex = byte - 96;
		else pacIndex = byte - 64;
		pacData.underline = (pacIndex & 1) === 1;
		if (pacIndex <= 13) pacData.color = [
			"white",
			"green",
			"blue",
			"cyan",
			"red",
			"yellow",
			"magenta",
			"white"
		][Math.floor(pacIndex / 2)];
		else if (pacIndex <= 15) {
			pacData.italics = true;
			pacData.color = "white";
		} else pacData.indent = Math.floor((pacIndex - 16) / 2) * 4;
		return pacData;
	}
	/**
	* Parse characters.
	* @returns An array with 1 to 2 codes corresponding to chars, if found. null otherwise.
	*/
	parseChars(a, b) {
		let channelNr;
		let charCodes = null;
		let charCode1 = null;
		if (a >= 25) {
			channelNr = 2;
			charCode1 = a - 8;
		} else {
			channelNr = 1;
			charCode1 = a;
		}
		if (charCode1 >= 17 && charCode1 <= 19) {
			let oneCode;
			if (charCode1 === 17) oneCode = b + 80;
			else if (charCode1 === 18) oneCode = b + 112;
			else oneCode = b + 144;
			this.logger.log(2, () => "Special char '" + getCharForByte(oneCode) + "' in channel " + channelNr);
			charCodes = [oneCode];
		} else if (a >= 32 && a <= 127) charCodes = b === 0 ? [a] : [a, b];
		if (charCodes) this.logger.log(3, () => "Char codes =  " + numArrayToHexArray(charCodes).join(","));
		return charCodes;
	}
	/**
	* Parse extended background attributes as well as new foreground color black.
	* @returns True if background attributes are found
	*/
	parseBackgroundAttributes(a, b) {
		if (!((a === 16 || a === 24) && b >= 32 && b <= 47 || (a === 23 || a === 31) && b >= 45 && b <= 47)) return false;
		let index;
		const bkgData = {};
		if (a === 16 || a === 24) {
			index = Math.floor((b - 32) / 2);
			bkgData.background = backgroundColors[index];
			if (b % 2 === 1) bkgData.background = bkgData.background + "_semi";
		} else if (b === 45) bkgData.background = "transparent";
		else {
			bkgData.foreground = "black";
			if (b === 47) bkgData.underline = true;
		}
		const chNr = a <= 23 ? 1 : 2;
		this.channels[chNr].setBkgData(bkgData);
		return true;
	}
	/**
	* Reset state of parser and its channels.
	*/
	reset() {
		for (let i = 0; i < Object.keys(this.channels).length; i++) {
			const channel = this.channels[i];
			if (channel) channel.reset();
		}
		setLastCmd(null, null, this.cmdHistory);
	}
	/**
	* Trigger the generation of a cue, and the start of a new one if displayScreens are not empty.
	*/
	cueSplitAtTime(t) {
		for (let i = 0; i < this.channels.length; i++) {
			const channel = this.channels[i];
			if (channel) channel.cueSplitAtTime(t);
		}
	}
};
function setLastCmd(a, b, cmdHistory) {
	cmdHistory.a = a;
	cmdHistory.b = b;
}
function hasCmdRepeated(a, b, cmdHistory) {
	return cmdHistory.a === a && cmdHistory.b === b;
}
function createCmdHistory() {
	return {
		a: null,
		b: null
	};
}
/**
* Copyright 2013 vtt.js Contributors
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var VTTCue = (function() {
	if (optionalSelf != null && optionalSelf.VTTCue) return self.VTTCue;
	const AllowedDirections = [
		"",
		"lr",
		"rl"
	];
	const AllowedAlignments = [
		"start",
		"middle",
		"end",
		"left",
		"right"
	];
	function isAllowedValue(allowed, value) {
		if (typeof value !== "string") return false;
		if (!Array.isArray(allowed)) return false;
		const lcValue = value.toLowerCase();
		if (~allowed.indexOf(lcValue)) return lcValue;
		return false;
	}
	function findDirectionSetting(value) {
		return isAllowedValue(AllowedDirections, value);
	}
	function findAlignSetting(value) {
		return isAllowedValue(AllowedAlignments, value);
	}
	function extend(obj, ...rest) {
		let i = 1;
		for (; i < arguments.length; i++) {
			const cobj = arguments[i];
			for (const p in cobj) obj[p] = cobj[p];
		}
		return obj;
	}
	function VTTCue(startTime, endTime, text) {
		const cue = this;
		const baseObj = { enumerable: true };
		/**
		* Shim implementation specific properties. These properties are not in
		* the spec.
		*/
		cue.hasBeenReset = false;
		/**
		* VTTCue and TextTrackCue properties
		* http://dev.w3.org/html5/webvtt/#vttcue-interface
		*/
		let _id = "";
		let _pauseOnExit = false;
		let _startTime = startTime;
		let _endTime = endTime;
		let _text = text;
		let _region = null;
		let _vertical = "";
		let _snapToLines = true;
		let _line = "auto";
		let _lineAlign = "start";
		let _position = 50;
		let _positionAlign = "middle";
		let _size = 50;
		let _align = "middle";
		Object.defineProperty(cue, "id", extend({}, baseObj, {
			get: function() {
				return _id;
			},
			set: function(value) {
				_id = "" + value;
			}
		}));
		Object.defineProperty(cue, "pauseOnExit", extend({}, baseObj, {
			get: function() {
				return _pauseOnExit;
			},
			set: function(value) {
				_pauseOnExit = !!value;
			}
		}));
		Object.defineProperty(cue, "startTime", extend({}, baseObj, {
			get: function() {
				return _startTime;
			},
			set: function(value) {
				if (typeof value !== "number") throw new TypeError("Start time must be set to a number.");
				_startTime = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "endTime", extend({}, baseObj, {
			get: function() {
				return _endTime;
			},
			set: function(value) {
				if (typeof value !== "number") throw new TypeError("End time must be set to a number.");
				_endTime = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "text", extend({}, baseObj, {
			get: function() {
				return _text;
			},
			set: function(value) {
				_text = "" + value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "region", extend({}, baseObj, {
			get: function() {
				return _region;
			},
			set: function(value) {
				_region = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "vertical", extend({}, baseObj, {
			get: function() {
				return _vertical;
			},
			set: function(value) {
				const setting = findDirectionSetting(value);
				if (setting === false) throw new SyntaxError("An invalid or illegal string was specified.");
				_vertical = setting;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "snapToLines", extend({}, baseObj, {
			get: function() {
				return _snapToLines;
			},
			set: function(value) {
				_snapToLines = !!value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "line", extend({}, baseObj, {
			get: function() {
				return _line;
			},
			set: function(value) {
				if (typeof value !== "number" && value !== "auto") throw new SyntaxError("An invalid number or illegal string was specified.");
				_line = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "lineAlign", extend({}, baseObj, {
			get: function() {
				return _lineAlign;
			},
			set: function(value) {
				const setting = findAlignSetting(value);
				if (!setting) throw new SyntaxError("An invalid or illegal string was specified.");
				_lineAlign = setting;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "position", extend({}, baseObj, {
			get: function() {
				return _position;
			},
			set: function(value) {
				if (value < 0 || value > 100) throw new Error("Position must be between 0 and 100.");
				_position = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "positionAlign", extend({}, baseObj, {
			get: function() {
				return _positionAlign;
			},
			set: function(value) {
				const setting = findAlignSetting(value);
				if (!setting) throw new SyntaxError("An invalid or illegal string was specified.");
				_positionAlign = setting;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "size", extend({}, baseObj, {
			get: function() {
				return _size;
			},
			set: function(value) {
				if (value < 0 || value > 100) throw new Error("Size must be between 0 and 100.");
				_size = value;
				this.hasBeenReset = true;
			}
		}));
		Object.defineProperty(cue, "align", extend({}, baseObj, {
			get: function() {
				return _align;
			},
			set: function(value) {
				const setting = findAlignSetting(value);
				if (!setting) throw new SyntaxError("An invalid or illegal string was specified.");
				_align = setting;
				this.hasBeenReset = true;
			}
		}));
		/**
		* Other  spec defined properties
		*/
		cue.displayState = void 0;
	}
	/**
	* VTTCue methods
	*/
	VTTCue.prototype.getCueAsHTML = function() {
		return self.WebVTT.convertCueToDOMTree(self, this.text);
	};
	return VTTCue;
})();
var StringDecoder = class {
	decode(data, options) {
		if (!data) return "";
		if (typeof data !== "string") throw new Error("Error - expected string data.");
		return decodeURIComponent(encodeURIComponent(data));
	}
};
function parseTimeStamp(input) {
	function computeSeconds(h, m, s, f) {
		return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + parseFloat(f || 0);
	}
	const m = input.match(/^(?:(\d+):)?(\d{2}):(\d{2})(\.\d+)?/);
	if (!m) return null;
	if (parseFloat(m[2]) > 59) return computeSeconds(m[2], m[3], 0, m[4]);
	return computeSeconds(m[1], m[2], m[3], m[4]);
}
var Settings = class {
	constructor() {
		this.values = Object.create(null);
	}
	set(k, v) {
		if (!this.get(k) && v !== "") this.values[k] = v;
	}
	get(k, dflt, defaultKey) {
		if (defaultKey) return this.has(k) ? this.values[k] : dflt[defaultKey];
		return this.has(k) ? this.values[k] : dflt;
	}
	has(k) {
		return k in this.values;
	}
	alt(k, v, a) {
		for (let n = 0; n < a.length; ++n) if (v === a[n]) {
			this.set(k, v);
			break;
		}
	}
	integer(k, v) {
		if (/^-?\d+$/.test(v)) this.set(k, parseInt(v, 10));
	}
	percent(k, v) {
		if (/^([\d]{1,3})(\.[\d]*)?%$/.test(v)) {
			const percent = parseFloat(v);
			if (percent >= 0 && percent <= 100) {
				this.set(k, percent);
				return true;
			}
		}
		return false;
	}
};
function parseOptions(input, callback, keyValueDelim, groupDelim) {
	const groups = groupDelim ? input.split(groupDelim) : [input];
	for (const i in groups) {
		if (typeof groups[i] !== "string") continue;
		const kv = groups[i].split(keyValueDelim);
		if (kv.length !== 2) continue;
		const k = kv[0];
		const v = kv[1];
		callback(k, v);
	}
}
var defaults = new VTTCue(0, 0, "");
var center = defaults.align === "middle" ? "middle" : "center";
function parseCue(input, cue, regionList) {
	const oInput = input;
	function consumeTimeStamp() {
		const ts = parseTimeStamp(input);
		if (ts === null) throw new Error("Malformed timestamp: " + oInput);
		input = input.replace(/^[^\sa-zA-Z-]+/, "");
		return ts;
	}
	function consumeCueSettings(input, cue) {
		const settings = new Settings();
		parseOptions(input, function(k, v) {
			let vals;
			switch (k) {
				case "region":
					for (let i = regionList.length - 1; i >= 0; i--) if (regionList[i].id === v) {
						settings.set(k, regionList[i].region);
						break;
					}
					break;
				case "vertical":
					settings.alt(k, v, ["rl", "lr"]);
					break;
				case "line":
					vals = v.split(",");
					settings.integer(k, vals[0]);
					if (settings.percent(k, vals[0])) settings.set("snapToLines", false);
					settings.alt(k, vals[0], ["auto"]);
					if (vals.length === 2) settings.alt("lineAlign", vals[1], [
						"start",
						center,
						"end"
					]);
					break;
				case "position":
					vals = v.split(",");
					settings.percent(k, vals[0]);
					if (vals.length === 2) settings.alt("positionAlign", vals[1], [
						"start",
						center,
						"end",
						"line-left",
						"line-right",
						"auto"
					]);
					break;
				case "size":
					settings.percent(k, v);
					break;
				case "align":
					settings.alt(k, v, [
						"start",
						center,
						"end",
						"left",
						"right"
					]);
					break;
			}
		}, /:/, /\s/);
		cue.region = settings.get("region", null);
		cue.vertical = settings.get("vertical", "");
		let line = settings.get("line", "auto");
		if (line === "auto" && defaults.line === -1) line = -1;
		cue.line = line;
		cue.lineAlign = settings.get("lineAlign", "start");
		cue.snapToLines = settings.get("snapToLines", true);
		cue.size = settings.get("size", 100);
		cue.align = settings.get("align", center);
		let position = settings.get("position", "auto");
		if (position === "auto" && defaults.position === 50) position = cue.align === "start" || cue.align === "left" ? 0 : cue.align === "end" || cue.align === "right" ? 100 : 50;
		cue.position = position;
	}
	function skipWhitespace() {
		input = input.replace(/^\s+/, "");
	}
	skipWhitespace();
	cue.startTime = consumeTimeStamp();
	skipWhitespace();
	if (input.slice(0, 3) !== "-->") throw new Error("Malformed time stamp (time stamps must be separated by '-->'): " + oInput);
	input = input.slice(3);
	skipWhitespace();
	cue.endTime = consumeTimeStamp();
	skipWhitespace();
	consumeCueSettings(input, cue);
}
function fixLineBreaks(input) {
	return input.replace(//gi, "\n");
}
var VTTParser = class {
	constructor() {
		this.state = "INITIAL";
		this.buffer = "";
		this.decoder = new StringDecoder();
		this.regionList = [];
		this.cue = null;
		this.oncue = void 0;
		this.onparsingerror = void 0;
		this.onflush = void 0;
	}
	parse(data) {
		const _this = this;
		if (data) _this.buffer += _this.decoder.decode(data, { stream: true });
		function collectNextLine() {
			let buffer = _this.buffer;
			let pos = 0;
			buffer = fixLineBreaks(buffer);
			while (pos < buffer.length && buffer[pos] !== "\r" && buffer[pos] !== "\n") ++pos;
			const line = buffer.slice(0, pos);
			if (buffer[pos] === "\r") ++pos;
			if (buffer[pos] === "\n") ++pos;
			_this.buffer = buffer.slice(pos);
			return line;
		}
		function parseHeader(input) {
			parseOptions(input, function(k, v) {}, /:/);
		}
		try {
			let line = "";
			if (_this.state === "INITIAL") {
				if (!/\r\n|\n/.test(_this.buffer)) return this;
				line = collectNextLine();
				const m = line.match(/^()?WEBVTT([ \t].*)?$/);
				if (!(m != null && m[0])) throw new Error("Malformed WebVTT signature.");
				_this.state = "HEADER";
			}
			let alreadyCollectedLine = false;
			while (_this.buffer) {
				if (!/\r\n|\n/.test(_this.buffer)) return this;
				if (!alreadyCollectedLine) line = collectNextLine();
				else alreadyCollectedLine = false;
				switch (_this.state) {
					case "HEADER":
						if (/:/.test(line)) parseHeader(line);
						else if (!line) _this.state = "ID";
						continue;
					case "NOTE":
						if (!line) _this.state = "ID";
						continue;
					case "ID":
						if (/^NOTE($|[ \t])/.test(line)) {
							_this.state = "NOTE";
							break;
						}
						if (!line) continue;
						_this.cue = new VTTCue(0, 0, "");
						_this.state = "CUE";
						if (line.indexOf("-->") === -1) {
							_this.cue.id = line;
							continue;
						}
					case "CUE":
						if (!_this.cue) {
							_this.state = "BADCUE";
							continue;
						}
						try {
							parseCue(line, _this.cue, _this.regionList);
						} catch (e) {
							_this.cue = null;
							_this.state = "BADCUE";
							continue;
						}
						_this.state = "CUETEXT";
						continue;
					case "CUETEXT":
						{
							const hasSubstring = line.indexOf("-->") !== -1;
							if (!line || hasSubstring && (alreadyCollectedLine = true)) {
								if (_this.oncue && _this.cue) _this.oncue(_this.cue);
								_this.cue = null;
								_this.state = "ID";
								continue;
							}
							if (_this.cue === null) continue;
							if (_this.cue.text) _this.cue.text += "\n";
							_this.cue.text += line;
						}
						continue;
					case "BADCUE": if (!line) _this.state = "ID";
				}
			}
		} catch (e) {
			if (_this.state === "CUETEXT" && _this.cue && _this.oncue) _this.oncue(_this.cue);
			_this.cue = null;
			_this.state = _this.state === "INITIAL" ? "BADWEBVTT" : "BADCUE";
		}
		return this;
	}
	flush() {
		const _this = this;
		try {
			if (_this.cue || _this.state === "HEADER") {
				_this.buffer += "\n\n";
				_this.parse();
			}
			if (_this.state === "INITIAL" || _this.state === "BADWEBVTT") throw new Error("Malformed WebVTT signature.");
		} catch (e) {
			if (_this.onparsingerror) _this.onparsingerror(e);
		}
		if (_this.onflush) _this.onflush();
		return this;
	}
};
var LINEBREAKS = /\r\n|\n\r|\n|\r/g;
var startsWith = function startsWith(inputString, searchString, position = 0) {
	return inputString.slice(position, position + searchString.length) === searchString;
};
var cueString2millis = function cueString2millis(timeString) {
	let ts = parseInt(timeString.slice(-3));
	const secs = parseInt(timeString.slice(-6, -4));
	const mins = parseInt(timeString.slice(-9, -7));
	const hours = timeString.length > 9 ? parseInt(timeString.substring(0, timeString.indexOf(":"))) : 0;
	if (!isFiniteNumber(ts) || !isFiniteNumber(secs) || !isFiniteNumber(mins) || !isFiniteNumber(hours)) throw Error(`Malformed X-TIMESTAMP-MAP: Local:${timeString}`);
	ts += 1e3 * secs;
	ts += 60 * 1e3 * mins;
	ts += 3600 * 1e3 * hours;
	return ts;
};
function generateCueId(startTime, endTime, text) {
	return hash(startTime.toString()) + hash(endTime.toString()) + hash(text);
}
var calculateOffset$2 = function calculateOffset(vttCCs, cc, presentationTime) {
	let currCC = vttCCs[cc];
	let prevCC = vttCCs[currCC.prevCC];
	if (!prevCC || !prevCC.new && currCC.new) {
		vttCCs.ccOffset = vttCCs.presentationOffset = currCC.start;
		currCC.new = false;
		return;
	}
	while ((_prevCC = prevCC) != null && _prevCC.new) {
		var _prevCC;
		vttCCs.ccOffset += currCC.start - prevCC.start;
		currCC.new = false;
		currCC = prevCC;
		prevCC = vttCCs[currCC.prevCC];
	}
	vttCCs.presentationOffset = presentationTime;
};
function parseWebVTT(vttByteArray, initPTS, vttCCs, cc, timeOffset, callBack, errorCallBack) {
	const parser = new VTTParser();
	const vttLines = utf8ArrayToStr(new Uint8Array(vttByteArray)).trim().replace(LINEBREAKS, "\n").split("\n");
	const cues = [];
	const init90kHz = initPTS ? toMpegTsClockFromTimescale(initPTS.baseTime, initPTS.timescale) : 0;
	let cueTime = "00:00.000";
	let timestampMapMPEGTS = 0;
	let timestampMapLOCAL = 0;
	let parsingError;
	let inHeader = true;
	parser.oncue = function(cue) {
		const currCC = vttCCs[cc];
		let cueOffset = vttCCs.ccOffset;
		const webVttMpegTsMapOffset = (timestampMapMPEGTS - init90kHz) / 9e4;
		if (currCC != null && currCC.new) if (timestampMapLOCAL !== void 0) cueOffset = vttCCs.ccOffset = currCC.start;
		else calculateOffset$2(vttCCs, cc, webVttMpegTsMapOffset);
		if (webVttMpegTsMapOffset) {
			if (!initPTS) {
				parsingError = /* @__PURE__ */ new Error("Missing initPTS for VTT MPEGTS");
				return;
			}
			cueOffset = webVttMpegTsMapOffset - vttCCs.presentationOffset;
		}
		const duration = cue.endTime - cue.startTime;
		const startTime = normalizePts((cue.startTime + cueOffset - timestampMapLOCAL) * 9e4, timeOffset * 9e4) / 9e4;
		cue.startTime = Math.max(startTime, 0);
		cue.endTime = Math.max(startTime + duration, 0);
		const text = cue.text.trim();
		cue.text = decodeURIComponent(encodeURIComponent(text));
		if (!cue.id) cue.id = generateCueId(cue.startTime, cue.endTime, text);
		if (cue.endTime > 0) cues.push(cue);
	};
	parser.onparsingerror = function(error) {
		parsingError = error;
	};
	parser.onflush = function() {
		if (parsingError) {
			errorCallBack(parsingError);
			return;
		}
		callBack(cues);
	};
	vttLines.forEach((line) => {
		if (inHeader) {
			if (startsWith(line, "X-TIMESTAMP-MAP=")) {
				inHeader = false;
				line.slice(16).split(",").forEach((timestamp) => {
					if (startsWith(timestamp, "LOCAL:")) cueTime = timestamp.slice(6);
					else if (startsWith(timestamp, "MPEGTS:")) timestampMapMPEGTS = parseInt(timestamp.slice(7));
				});
				try {
					timestampMapLOCAL = cueString2millis(cueTime) / 1e3;
				} catch (error) {
					parsingError = error;
				}
				return;
			} else if (line === "") inHeader = false;
		}
		parser.parse(line + "\n");
	});
	parser.flush();
}
var IMSC1_CODEC = "stpp.ttml.im1t";
var HMSF_REGEX = /^(\d{2,}):(\d{2}):(\d{2}):(\d{2})\.?(\d+)?$/;
var TIME_UNIT_REGEX = /^(\d*(?:\.\d*)?)(h|m|s|ms|f|t)$/;
var textAlignToLineAlign = {
	left: "start",
	center: "center",
	right: "end",
	start: "start",
	end: "end"
};
function parseIMSC1(payload, initPTS, callBack, errorCallBack) {
	const results = findBox(new Uint8Array(payload), ["mdat"]);
	if (results.length === 0) {
		errorCallBack(/* @__PURE__ */ new Error("Could not parse IMSC1 mdat"));
		return;
	}
	const ttmlList = results.map((mdat) => utf8ArrayToStr(mdat));
	const syncTime = toTimescaleFromScale(initPTS.baseTime, 1, initPTS.timescale);
	try {
		ttmlList.forEach((ttml) => callBack(parseTTML(ttml, syncTime)));
	} catch (error) {
		errorCallBack(error);
	}
}
function parseTTML(ttml, syncTime) {
	const tt = new DOMParser().parseFromString(ttml, "text/xml").getElementsByTagName("tt")[0];
	if (!tt) throw new Error("Invalid ttml");
	const defaultRateInfo = {
		frameRate: 30,
		subFrameRate: 1,
		frameRateMultiplier: 0,
		tickRate: 0
	};
	const rateInfo = Object.keys(defaultRateInfo).reduce((result, key) => {
		result[key] = tt.getAttribute(`ttp:${key}`) || defaultRateInfo[key];
		return result;
	}, {});
	const trim = tt.getAttribute("xml:space") !== "preserve";
	const styleElements = collectionToDictionary(getElementCollection(tt, "styling", "style"));
	const regionElements = collectionToDictionary(getElementCollection(tt, "layout", "region"));
	const cueElements = getElementCollection(tt, "body", "[begin]");
	return [].map.call(cueElements, (cueElement) => {
		const cueText = getTextContent(cueElement, trim);
		if (!cueText || !cueElement.hasAttribute("begin")) return null;
		const startTime = parseTtmlTime(cueElement.getAttribute("begin"), rateInfo);
		const duration = parseTtmlTime(cueElement.getAttribute("dur"), rateInfo);
		let endTime = parseTtmlTime(cueElement.getAttribute("end"), rateInfo);
		if (startTime === null) throw timestampParsingError(cueElement);
		if (endTime === null) {
			if (duration === null) throw timestampParsingError(cueElement);
			endTime = startTime + duration;
		}
		const cue = new VTTCue(startTime - syncTime, endTime - syncTime, cueText);
		cue.id = generateCueId(cue.startTime, cue.endTime, cue.text);
		const region = regionElements[cueElement.getAttribute("region")];
		const style = styleElements[cueElement.getAttribute("style")];
		const styles = getTtmlStyles(region, style, styleElements);
		const { textAlign } = styles;
		if (textAlign) {
			const lineAlign = textAlignToLineAlign[textAlign];
			if (lineAlign) cue.lineAlign = lineAlign;
			cue.align = textAlign;
		}
		_extends(cue, styles);
		return cue;
	}).filter((cue) => cue !== null);
}
function getElementCollection(fromElement, parentName, childName) {
	const parent = fromElement.getElementsByTagName(parentName)[0];
	if (parent) return [].slice.call(parent.querySelectorAll(childName));
	return [];
}
function collectionToDictionary(elementsWithId) {
	return elementsWithId.reduce((dict, element) => {
		const id = element.getAttribute("xml:id");
		if (id) dict[id] = element;
		return dict;
	}, {});
}
function getTextContent(element, trim) {
	return [].slice.call(element.childNodes).reduce((str, node, i) => {
		var _node$childNodes;
		if (node.nodeName === "br" && i) return str + "\n";
		if ((_node$childNodes = node.childNodes) != null && _node$childNodes.length) return getTextContent(node, trim);
		else if (trim) return str + node.textContent.trim().replace(/\s+/g, " ");
		return str + node.textContent;
	}, "");
}
function getTtmlStyles(region, style, styleElements) {
	const ttsNs = "http://www.w3.org/ns/ttml#styling";
	let regionStyle = null;
	const styleAttributes = [
		"displayAlign",
		"textAlign",
		"color",
		"backgroundColor",
		"fontSize",
		"fontFamily"
	];
	const regionStyleName = region != null && region.hasAttribute("style") ? region.getAttribute("style") : null;
	if (regionStyleName && styleElements.hasOwnProperty(regionStyleName)) regionStyle = styleElements[regionStyleName];
	return styleAttributes.reduce((styles, name) => {
		const value = getAttributeNS(style, ttsNs, name) || getAttributeNS(region, ttsNs, name) || getAttributeNS(regionStyle, ttsNs, name);
		if (value) styles[name] = value;
		return styles;
	}, {});
}
function getAttributeNS(element, ns, name) {
	if (!element) return null;
	return element.hasAttributeNS(ns, name) ? element.getAttributeNS(ns, name) : null;
}
function timestampParsingError(node) {
	return /* @__PURE__ */ new Error(`Could not parse ttml timestamp ${node}`);
}
function parseTtmlTime(timeAttributeValue, rateInfo) {
	if (!timeAttributeValue) return null;
	let seconds = parseTimeStamp(timeAttributeValue);
	if (seconds === null) {
		if (HMSF_REGEX.test(timeAttributeValue)) seconds = parseHoursMinutesSecondsFrames(timeAttributeValue, rateInfo);
		else if (TIME_UNIT_REGEX.test(timeAttributeValue)) seconds = parseTimeUnits(timeAttributeValue, rateInfo);
	}
	return seconds;
}
function parseHoursMinutesSecondsFrames(timeAttributeValue, rateInfo) {
	const m = HMSF_REGEX.exec(timeAttributeValue);
	const frames = (m[4] | 0) + (m[5] | 0) / rateInfo.subFrameRate;
	return (m[1] | 0) * 3600 + (m[2] | 0) * 60 + (m[3] | 0) + frames / rateInfo.frameRate;
}
function parseTimeUnits(timeAttributeValue, rateInfo) {
	const m = TIME_UNIT_REGEX.exec(timeAttributeValue);
	const value = Number(m[1]);
	switch (m[2]) {
		case "h": return value * 3600;
		case "m": return value * 60;
		case "ms": return value * 1e3;
		case "f": return value / rateInfo.frameRate;
		case "t": return value / rateInfo.tickRate;
	}
	return value;
}
var OutputFilter = class {
	constructor(timelineController, trackName) {
		this.timelineController = void 0;
		this.cueRanges = [];
		this.trackName = void 0;
		this.startTime = null;
		this.endTime = null;
		this.screen = null;
		this.timelineController = timelineController;
		this.trackName = trackName;
	}
	dispatchCue() {
		if (this.startTime === null) return;
		this.timelineController.addCues(this.trackName, this.startTime, this.endTime, this.screen, this.cueRanges);
		this.startTime = null;
	}
	newCue(startTime, endTime, screen) {
		if (this.startTime === null || this.startTime > startTime) this.startTime = startTime;
		this.endTime = endTime;
		this.screen = screen;
		this.timelineController.createCaptionsTrack(this.trackName);
	}
	reset() {
		this.cueRanges = [];
		this.startTime = null;
	}
};
var TimelineController = class {
	constructor(hls) {
		this.hls = void 0;
		this.media = null;
		this.config = void 0;
		this.enabled = true;
		this.Cues = void 0;
		this.textTracks = [];
		this.tracks = [];
		this.initPTS = [];
		this.unparsedVttFrags = [];
		this.captionsTracks = {};
		this.nonNativeCaptionsTracks = {};
		this.cea608Parser1 = void 0;
		this.cea608Parser2 = void 0;
		this.lastCc = -1;
		this.lastSn = -1;
		this.lastPartIndex = -1;
		this.prevCC = -1;
		this.vttCCs = newVTTCCs();
		this.captionsProperties = void 0;
		this.hls = hls;
		this.config = hls.config;
		this.Cues = hls.config.cueHandler;
		this.captionsProperties = {
			textTrack1: {
				label: this.config.captionsTextTrack1Label,
				languageCode: this.config.captionsTextTrack1LanguageCode
			},
			textTrack2: {
				label: this.config.captionsTextTrack2Label,
				languageCode: this.config.captionsTextTrack2LanguageCode
			},
			textTrack3: {
				label: this.config.captionsTextTrack3Label,
				languageCode: this.config.captionsTextTrack3LanguageCode
			},
			textTrack4: {
				label: this.config.captionsTextTrack4Label,
				languageCode: this.config.captionsTextTrack4LanguageCode
			}
		};
		hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
		hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
		hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
		hls.on(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
		hls.on(Events.FRAG_LOADING, this.onFragLoading, this);
		hls.on(Events.FRAG_LOADED, this.onFragLoaded, this);
		hls.on(Events.FRAG_PARSING_USERDATA, this.onFragParsingUserdata, this);
		hls.on(Events.FRAG_DECRYPTED, this.onFragDecrypted, this);
		hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this);
		hls.on(Events.SUBTITLE_TRACKS_CLEARED, this.onSubtitleTracksCleared, this);
		hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
	}
	destroy() {
		const { hls } = this;
		hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
		hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
		hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
		hls.off(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
		hls.off(Events.FRAG_LOADING, this.onFragLoading, this);
		hls.off(Events.FRAG_LOADED, this.onFragLoaded, this);
		hls.off(Events.FRAG_PARSING_USERDATA, this.onFragParsingUserdata, this);
		hls.off(Events.FRAG_DECRYPTED, this.onFragDecrypted, this);
		hls.off(Events.INIT_PTS_FOUND, this.onInitPtsFound, this);
		hls.off(Events.SUBTITLE_TRACKS_CLEARED, this.onSubtitleTracksCleared, this);
		hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
		this.hls = this.config = this.media = null;
		this.cea608Parser1 = this.cea608Parser2 = void 0;
	}
	initCea608Parsers() {
		const channel1 = new OutputFilter(this, "textTrack1");
		const channel2 = new OutputFilter(this, "textTrack2");
		const channel3 = new OutputFilter(this, "textTrack3");
		const channel4 = new OutputFilter(this, "textTrack4");
		this.cea608Parser1 = new Cea608Parser(1, channel1, channel2);
		this.cea608Parser2 = new Cea608Parser(3, channel3, channel4);
	}
	addCues(trackName, startTime, endTime, screen, cueRanges) {
		let merged = false;
		for (let i = cueRanges.length; i--;) {
			const cueRange = cueRanges[i];
			const overlap = intersection$2(cueRange[0], cueRange[1], startTime, endTime);
			if (overlap >= 0) {
				cueRange[0] = Math.min(cueRange[0], startTime);
				cueRange[1] = Math.max(cueRange[1], endTime);
				merged = true;
				if (overlap / (endTime - startTime) > .5) return;
			}
		}
		if (!merged) cueRanges.push([startTime, endTime]);
		if (this.config.renderTextTracksNatively) {
			const track = this.captionsTracks[trackName];
			this.Cues.newCue(track, startTime, endTime, screen);
		} else {
			const cues = this.Cues.newCue(null, startTime, endTime, screen);
			this.hls.trigger(Events.CUES_PARSED, {
				type: "captions",
				cues,
				track: trackName
			});
		}
	}
	onInitPtsFound(event, { frag, id, initPTS, timescale, trackId }) {
		const { unparsedVttFrags } = this;
		if (id === PlaylistLevelType.MAIN) this.initPTS[frag.cc] = {
			baseTime: initPTS,
			timescale,
			trackId
		};
		if (unparsedVttFrags.length) {
			this.unparsedVttFrags = [];
			unparsedVttFrags.forEach((data) => {
				if (this.initPTS[data.frag.cc]) this.onFragLoaded(Events.FRAG_LOADED, data);
				else this.hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
					success: false,
					frag: data.frag,
					error: /* @__PURE__ */ new Error("Subtitle discontinuity domain does not match main")
				});
			});
		}
	}
	getExistingTrack(label, language) {
		const { media } = this;
		if (media) for (let i = 0; i < media.textTracks.length; i++) {
			const textTrack = media.textTracks[i];
			if (canReuseVttTextTrack(textTrack, {
				name: label,
				lang: language,
				characteristics: "transcribes-spoken-dialog,describes-music-and-sound"
			})) return textTrack;
		}
		return null;
	}
	createCaptionsTrack(trackName) {
		if (this.config.renderTextTracksNatively) this.createNativeTrack(trackName);
		else this.createNonNativeTrack(trackName);
	}
	createNativeTrack(trackName) {
		if (this.captionsTracks[trackName]) return;
		const { captionsProperties, captionsTracks, media } = this;
		const { label, languageCode } = captionsProperties[trackName];
		const existingTrack = this.getExistingTrack(label, languageCode);
		if (!existingTrack) {
			const textTrack = this.createTextTrack("captions", label, languageCode);
			if (textTrack) {
				textTrack[trackName] = true;
				captionsTracks[trackName] = textTrack;
			}
		} else {
			captionsTracks[trackName] = existingTrack;
			clearCurrentCues(captionsTracks[trackName]);
			sendAddTrackEvent(captionsTracks[trackName], media);
		}
	}
	createNonNativeTrack(trackName) {
		if (this.nonNativeCaptionsTracks[trackName]) return;
		const trackProperties = this.captionsProperties[trackName];
		if (!trackProperties) return;
		const track = {
			_id: trackName,
			label: trackProperties.label,
			kind: "captions",
			default: trackProperties.media ? !!trackProperties.media.default : false,
			closedCaptions: trackProperties.media
		};
		this.nonNativeCaptionsTracks[trackName] = track;
		this.hls.trigger(Events.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: [track] });
	}
	createTextTrack(kind, label, lang) {
		const media = this.media;
		if (!media) return;
		return media.addTextTrack(kind, label, lang);
	}
	onMediaAttaching(event, data) {
		this.media = data.media;
		if (!data.mediaSource) this._cleanTracks();
	}
	onMediaDetaching(event, data) {
		const transferringMedia = !!data.transferMedia;
		this.media = null;
		if (transferringMedia) return;
		const { captionsTracks } = this;
		Object.keys(captionsTracks).forEach((trackName) => {
			clearCurrentCues(captionsTracks[trackName]);
			delete captionsTracks[trackName];
		});
		this.nonNativeCaptionsTracks = {};
	}
	onManifestLoading() {
		this.lastCc = -1;
		this.lastSn = -1;
		this.lastPartIndex = -1;
		this.prevCC = -1;
		this.vttCCs = newVTTCCs();
		this._cleanTracks();
		this.tracks = [];
		this.captionsTracks = {};
		this.nonNativeCaptionsTracks = {};
		this.textTracks = [];
		this.unparsedVttFrags = [];
		this.initPTS = [];
		if (this.cea608Parser1 && this.cea608Parser2) {
			this.cea608Parser1.reset();
			this.cea608Parser2.reset();
		}
	}
	_cleanTracks() {
		const { media } = this;
		if (!media) return;
		const textTracks = media.textTracks;
		if (textTracks) for (let i = 0; i < textTracks.length; i++) clearCurrentCues(textTracks[i]);
	}
	onSubtitleTracksUpdated(event, data) {
		const tracks = data.subtitleTracks || [];
		const hasIMSC1 = tracks.some((track) => track.textCodec === IMSC1_CODEC);
		if (this.config.enableWebVTT || hasIMSC1 && this.config.enableIMSC1) {
			if (subtitleOptionsIdentical(this.tracks, tracks)) {
				this.tracks = tracks;
				return;
			}
			this.textTracks = [];
			this.tracks = tracks;
			if (this.config.renderTextTracksNatively) {
				const media = this.media;
				const inUseTracks = media ? filterSubtitleTracks(media.textTracks) : null;
				this.tracks.forEach((track, index) => {
					let textTrack;
					if (inUseTracks) {
						let inUseTrack = null;
						for (let i = 0; i < inUseTracks.length; i++) if (inUseTracks[i] && canReuseVttTextTrack(inUseTracks[i], track)) {
							inUseTrack = inUseTracks[i];
							inUseTracks[i] = null;
							break;
						}
						if (inUseTrack) textTrack = inUseTrack;
					}
					if (textTrack) clearCurrentCues(textTrack);
					else {
						const textTrackKind = captionsOrSubtitlesFromCharacteristics(track);
						textTrack = this.createTextTrack(textTrackKind, track.name, track.lang);
						if (textTrack) textTrack.mode = "disabled";
					}
					if (textTrack) this.textTracks.push(textTrack);
				});
				if (inUseTracks != null && inUseTracks.length) {
					const unusedTextTracks = inUseTracks.filter((t) => t !== null).map((t) => t.label);
					if (unusedTextTracks.length) this.hls.logger.warn(`Media element contains unused subtitle tracks: ${unusedTextTracks.join(", ")}. Replace media element for each source to clear TextTracks and captions menu.`);
				}
			} else if (this.tracks.length) {
				const tracksList = this.tracks.map((track) => {
					return {
						label: track.name,
						kind: track.type.toLowerCase(),
						default: track.default,
						subtitleTrack: track
					};
				});
				this.hls.trigger(Events.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: tracksList });
			}
		}
	}
	onManifestLoaded(event, data) {
		if (this.config.enableCEA708Captions && data.captions) data.captions.forEach((captionsTrack) => {
			const instreamIdMatch = /(?:CC|SERVICE)([1-4])/.exec(captionsTrack.instreamId);
			if (!instreamIdMatch) return;
			const trackName = `textTrack${instreamIdMatch[1]}`;
			const trackProperties = this.captionsProperties[trackName];
			if (!trackProperties) return;
			trackProperties.label = captionsTrack.name;
			if (captionsTrack.lang) trackProperties.languageCode = captionsTrack.lang;
			trackProperties.media = captionsTrack;
		});
	}
	closedCaptionsForLevel(frag) {
		const level = this.hls.levels[frag.level];
		return level == null ? void 0 : level.attrs["CLOSED-CAPTIONS"];
	}
	onFragLoading(event, data) {
		if (this.enabled && data.frag.type === PlaylistLevelType.MAIN) {
			var _data$part$index, _data$part;
			const { cea608Parser1, cea608Parser2, lastSn } = this;
			const { cc, sn } = data.frag;
			const partIndex = (_data$part$index = (_data$part = data.part) == null ? void 0 : _data$part.index) != null ? _data$part$index : -1;
			if (cea608Parser1 && cea608Parser2) {
				if (sn !== lastSn + 1 || sn === lastSn && partIndex !== this.lastPartIndex + 1 || cc !== this.lastCc) {
					cea608Parser1.reset();
					cea608Parser2.reset();
				}
			}
			this.lastCc = cc;
			this.lastSn = sn;
			this.lastPartIndex = partIndex;
		}
	}
	onFragLoaded(event, data) {
		const { frag, payload } = data;
		if (frag.type === PlaylistLevelType.SUBTITLE) if (payload.byteLength) {
			const decryptData = frag.decryptdata;
			const decrypted = "stats" in data;
			if (decryptData == null || !decryptData.encrypted || decrypted) {
				const trackPlaylistMedia = this.tracks[frag.level];
				const vttCCs = this.vttCCs;
				if (!vttCCs[frag.cc]) {
					vttCCs[frag.cc] = {
						start: frag.start,
						prevCC: this.prevCC,
						new: true
					};
					this.prevCC = frag.cc;
				}
				if (trackPlaylistMedia && trackPlaylistMedia.textCodec === IMSC1_CODEC) this._parseIMSC1(frag, payload);
				else this._parseVTTs(data);
			}
		} else this.hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
			success: false,
			frag,
			error: /* @__PURE__ */ new Error("Empty subtitle payload")
		});
	}
	_parseIMSC1(frag, payload) {
		const hls = this.hls;
		parseIMSC1(payload, this.initPTS[frag.cc], (cues) => {
			this._appendCues(cues, frag.level);
			hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
				success: true,
				frag
			});
		}, (error) => {
			hls.logger.log(`Failed to parse IMSC1: ${error}`);
			hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
				success: false,
				frag,
				error
			});
		});
	}
	_parseVTTs(data) {
		var _frag$initSegment;
		const { frag, payload } = data;
		const { initPTS, unparsedVttFrags } = this;
		const maxAvCC = initPTS.length - 1;
		if (!initPTS[frag.cc] && maxAvCC === -1) {
			unparsedVttFrags.push(data);
			return;
		}
		const hls = this.hls;
		parseWebVTT((_frag$initSegment = frag.initSegment) != null && _frag$initSegment.data ? appendUint8Array(frag.initSegment.data, new Uint8Array(payload)).buffer : payload, this.initPTS[frag.cc], this.vttCCs, frag.cc, frag.start, (cues) => {
			this._appendCues(cues, frag.level);
			hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
				success: true,
				frag
			});
		}, (error) => {
			const missingInitPTS = error.message === "Missing initPTS for VTT MPEGTS";
			if (missingInitPTS) unparsedVttFrags.push(data);
			else this._fallbackToIMSC1(frag, payload);
			hls.logger.log(`Failed to parse VTT cue: ${error}`);
			if (missingInitPTS && maxAvCC > frag.cc) return;
			hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
				success: false,
				frag,
				error
			});
		});
	}
	_fallbackToIMSC1(frag, payload) {
		const trackPlaylistMedia = this.tracks[frag.level];
		if (!trackPlaylistMedia.textCodec) parseIMSC1(payload, this.initPTS[frag.cc], () => {
			trackPlaylistMedia.textCodec = IMSC1_CODEC;
			this._parseIMSC1(frag, payload);
		}, () => {
			trackPlaylistMedia.textCodec = "wvtt";
		});
	}
	_appendCues(cues, fragLevel) {
		const hls = this.hls;
		if (this.config.renderTextTracksNatively) {
			const textTrack = this.textTracks[fragLevel];
			if (!textTrack || textTrack.mode === "disabled") return;
			cues.forEach((cue) => addCueToTrack(textTrack, cue));
		} else {
			const currentTrack = this.tracks[fragLevel];
			if (!currentTrack) return;
			const track = currentTrack.default ? "default" : "subtitles" + fragLevel;
			hls.trigger(Events.CUES_PARSED, {
				type: "subtitles",
				cues,
				track
			});
		}
	}
	onFragDecrypted(event, data) {
		const { frag } = data;
		if (frag.type === PlaylistLevelType.SUBTITLE) this.onFragLoaded(Events.FRAG_LOADED, data);
	}
	onSubtitleTracksCleared() {
		this.tracks = [];
		this.captionsTracks = {};
	}
	onFragParsingUserdata(event, data) {
		if (!this.enabled || !this.config.enableCEA708Captions) return;
		const { frag, samples } = data;
		if (frag.type === PlaylistLevelType.MAIN && this.closedCaptionsForLevel(frag) === "NONE") return;
		for (let i = 0; i < samples.length; i++) {
			const ccBytes = samples[i].bytes;
			if (ccBytes) {
				if (!this.cea608Parser1) this.initCea608Parsers();
				const ccdatas = this.extractCea608Data(ccBytes);
				this.cea608Parser1.addData(samples[i].pts, ccdatas[0]);
				this.cea608Parser2.addData(samples[i].pts, ccdatas[1]);
			}
		}
	}
	onBufferFlushing(event, { startOffset, endOffset, endOffsetSubtitles, type }) {
		const { media } = this;
		if (!media || media.currentTime < endOffset) return;
		if (!type || type === "video") {
			const { captionsTracks } = this;
			Object.keys(captionsTracks).forEach((trackName) => removeCuesInRange(captionsTracks[trackName], startOffset, endOffset));
		}
		if (this.config.renderTextTracksNatively) {
			if (startOffset === 0 && endOffsetSubtitles !== void 0) {
				const { textTracks } = this;
				Object.keys(textTracks).forEach((trackName) => removeCuesInRange(textTracks[trackName], startOffset, endOffsetSubtitles));
			}
		}
	}
	extractCea608Data(byteArray) {
		const actualCCBytes = [[], []];
		const count = byteArray[0] & 31;
		let position = 2;
		for (let j = 0; j < count; j++) {
			const tmpByte = byteArray[position++];
			const ccbyte1 = 127 & byteArray[position++];
			const ccbyte2 = 127 & byteArray[position++];
			if (ccbyte1 === 0 && ccbyte2 === 0) continue;
			if ((4 & tmpByte) !== 0) {
				const ccType = 3 & tmpByte;
				if (0 === ccType || 1 === ccType) {
					actualCCBytes[ccType].push(ccbyte1);
					actualCCBytes[ccType].push(ccbyte2);
				}
			}
		}
		return actualCCBytes;
	}
};
function captionsOrSubtitlesFromCharacteristics(track) {
	if (track.characteristics) {
		if (/transcribes-spoken-dialog/gi.test(track.characteristics) && /describes-music-and-sound/gi.test(track.characteristics)) return "captions";
	}
	return "subtitles";
}
function canReuseVttTextTrack(inUseTrack, manifestTrack) {
	return !!inUseTrack && inUseTrack.kind === captionsOrSubtitlesFromCharacteristics(manifestTrack) && subtitleTrackMatchesTextTrack(manifestTrack, inUseTrack);
}
function intersection$2(x1, x2, y1, y2) {
	return Math.min(x2, y2) - Math.max(x1, y1);
}
function newVTTCCs() {
	return {
		ccOffset: 0,
		presentationOffset: 0,
		0: {
			start: 0,
			prevCC: -1,
			new: true
		}
	};
}
var WHITESPACE_CHAR = /\s/;
var Cues = { newCue(track, startTime, endTime, captionScreen) {
	const result = [];
	let row;
	let cue;
	let indenting;
	let indent;
	let text;
	const Cue = self.VTTCue || self.TextTrackCue;
	for (let r = 0; r < captionScreen.rows.length; r++) {
		row = captionScreen.rows[r];
		indenting = true;
		indent = 0;
		text = "";
		if (!row.isEmpty()) {
			var _track$cues;
			for (let c = 0; c < row.chars.length; c++) if (WHITESPACE_CHAR.test(row.chars[c].uchar) && indenting) indent++;
			else {
				text += row.chars[c].uchar;
				indenting = false;
			}
			row.cueStartTime = startTime;
			if (startTime === endTime) endTime += 1e-4;
			if (indent >= 16) indent--;
			else indent++;
			const cueText = fixLineBreaks(text.trim());
			const id = generateCueId(startTime, endTime, cueText);
			if (!(track != null && (_track$cues = track.cues) != null && _track$cues.getCueById(id))) {
				cue = new Cue(startTime, endTime, cueText);
				cue.id = id;
				cue.line = r + 1;
				cue.align = "left";
				cue.position = 10 + Math.min(80, Math.floor(indent * 8 / 32) * 10);
				result.push(cue);
			}
		}
	}
	if (track && result.length) {
		result.sort((cueA, cueB) => {
			if (cueA.line === "auto" || cueB.line === "auto") return 0;
			if (cueA.line > 8 && cueB.line > 8) return cueB.line - cueA.line;
			return cueA.line - cueB.line;
		});
		result.forEach((cue) => addCueToTrack(track, cue));
	}
	return result;
} };
function fetchSupported() {
	if (self.fetch && self.AbortController && self.ReadableStream && self.Request) try {
		new self.ReadableStream({});
		return true;
	} catch (e) {}
	return false;
}
var BYTERANGE = /(\d+)-(\d+)\/(\d+)/;
var FetchLoader = class {
	constructor(config) {
		this.fetchSetup = void 0;
		this.requestTimeout = void 0;
		this.request = null;
		this.response = null;
		this.controller = void 0;
		this.context = null;
		this.config = null;
		this.callbacks = null;
		this.stats = void 0;
		this.loader = null;
		this.fetchSetup = config.fetchSetup || getRequest;
		this.controller = new self.AbortController();
		this.stats = new LoadStats();
	}
	destroy() {
		this.loader = this.callbacks = this.context = this.config = this.request = null;
		this.abortInternal();
		this.response = null;
		this.fetchSetup = this.controller = this.stats = null;
	}
	abortInternal() {
		if (this.controller && !this.stats.loading.end) {
			this.stats.aborted = true;
			this.controller.abort();
		}
	}
	abort() {
		var _this$callbacks;
		this.abortInternal();
		if ((_this$callbacks = this.callbacks) != null && _this$callbacks.onAbort) this.callbacks.onAbort(this.stats, this.context, this.response);
	}
	load(context, config, callbacks) {
		const stats = this.stats;
		if (stats.loading.start) throw new Error("Loader can only be used once.");
		stats.loading.start = self.performance.now();
		const initParams = getRequestParameters(context, this.controller.signal);
		const isArrayBuffer = context.responseType === "arraybuffer";
		const LENGTH = isArrayBuffer ? "byteLength" : "length";
		const { maxTimeToFirstByteMs, maxLoadTimeMs } = config.loadPolicy;
		this.context = context;
		this.config = config;
		this.callbacks = callbacks;
		this.request = this.fetchSetup(context, initParams);
		self.clearTimeout(this.requestTimeout);
		config.timeout = maxTimeToFirstByteMs && isFiniteNumber(maxTimeToFirstByteMs) ? maxTimeToFirstByteMs : maxLoadTimeMs;
		this.requestTimeout = self.setTimeout(() => {
			if (this.callbacks) {
				this.abortInternal();
				this.callbacks.onTimeout(stats, context, this.response);
			}
		}, config.timeout);
		(isPromise(this.request) ? this.request.then(self.fetch) : self.fetch(this.request)).then((response) => {
			var _this$callbacks2;
			this.response = this.loader = response;
			const first = Math.max(self.performance.now(), stats.loading.start);
			self.clearTimeout(this.requestTimeout);
			config.timeout = maxLoadTimeMs;
			this.requestTimeout = self.setTimeout(() => {
				if (this.callbacks) {
					this.abortInternal();
					this.callbacks.onTimeout(stats, context, this.response);
				}
			}, maxLoadTimeMs - (first - stats.loading.start));
			if (!response.ok) {
				const { status, statusText } = response;
				throw new FetchError(statusText || "fetch, bad network response", status, response);
			}
			stats.loading.first = first;
			stats.total = getContentLength(response.headers) || stats.total;
			const onProgress = (_this$callbacks2 = this.callbacks) == null ? void 0 : _this$callbacks2.onProgress;
			if (onProgress && isFiniteNumber(config.highWaterMark)) return this.loadProgressively(response, stats, context, config.highWaterMark, onProgress);
			if (isArrayBuffer) return response.arrayBuffer();
			if (context.responseType === "json") return response.json();
			return response.text();
		}).then((responseData) => {
			var _this$callbacks3, _this$callbacks4;
			const response = this.response;
			if (!response) throw new Error("loader destroyed");
			self.clearTimeout(this.requestTimeout);
			stats.loading.end = Math.max(self.performance.now(), stats.loading.first);
			const total = responseData[LENGTH];
			if (total) stats.loaded = stats.total = total;
			const loaderResponse = {
				url: response.url,
				data: responseData,
				code: response.status
			};
			const onProgress = (_this$callbacks3 = this.callbacks) == null ? void 0 : _this$callbacks3.onProgress;
			if (onProgress && !isFiniteNumber(config.highWaterMark)) onProgress(stats, context, responseData, response);
			(_this$callbacks4 = this.callbacks) == null || _this$callbacks4.onSuccess(loaderResponse, stats, context, response);
		}).catch((error) => {
			var _this$callbacks5;
			self.clearTimeout(this.requestTimeout);
			if (stats.aborted) return;
			const code = !error ? 0 : error.code || 0;
			const text = !error ? null : error.message;
			(_this$callbacks5 = this.callbacks) == null || _this$callbacks5.onError({
				code,
				text
			}, context, error ? error.details : null, stats);
		});
	}
	getCacheAge() {
		let result = null;
		if (this.response) {
			const ageHeader = this.response.headers.get("age");
			result = ageHeader ? parseFloat(ageHeader) : null;
		}
		return result;
	}
	getResponseHeader(name) {
		return this.response ? this.response.headers.get(name) : null;
	}
	loadProgressively(response, stats, context, highWaterMark = 0, onProgress) {
		const chunkCache = new ChunkCache();
		const reader = response.body.getReader();
		const pump = () => {
			return reader.read().then((data) => {
				if (data.done) {
					if (chunkCache.dataLength) onProgress(stats, context, chunkCache.flush().buffer, response);
					return Promise.resolve(/* @__PURE__ */ new ArrayBuffer(0));
				}
				const chunk = data.value;
				const len = chunk.length;
				stats.loaded += len;
				if (len < highWaterMark || chunkCache.dataLength) {
					chunkCache.push(chunk);
					if (chunkCache.dataLength >= highWaterMark) onProgress(stats, context, chunkCache.flush().buffer, response);
				} else onProgress(stats, context, chunk.buffer, response);
				return pump();
			}).catch(() => {
				return Promise.reject();
			});
		};
		return pump();
	}
};
function getRequestParameters(context, signal) {
	const initParams = {
		method: "GET",
		mode: "cors",
		credentials: "same-origin",
		signal,
		headers: new self.Headers(_extends({}, context.headers))
	};
	if (context.rangeEnd) initParams.headers.set("Range", "bytes=" + context.rangeStart + "-" + String(context.rangeEnd - 1));
	return initParams;
}
function getByteRangeLength(byteRangeHeader) {
	const result = BYTERANGE.exec(byteRangeHeader);
	if (result) return parseInt(result[2]) - parseInt(result[1]) + 1;
}
function getContentLength(headers) {
	const contentRange = headers.get("Content-Range");
	if (contentRange) {
		const byteRangeLength = getByteRangeLength(contentRange);
		if (isFiniteNumber(byteRangeLength)) return byteRangeLength;
	}
	const contentLength = headers.get("Content-Length");
	if (contentLength) return parseInt(contentLength);
}
function getRequest(context, initParams) {
	return new self.Request(context.url, initParams);
}
var FetchError = class extends Error {
	constructor(message, code, details) {
		super(message);
		this.code = void 0;
		this.details = void 0;
		this.code = code;
		this.details = details;
	}
};
var AGE_HEADER_LINE_REGEX = /^age:\s*[\d.]+\s*$/im;
var XhrLoader = class {
	constructor(config) {
		this.xhrSetup = void 0;
		this.requestTimeout = void 0;
		this.retryTimeout = void 0;
		this.retryDelay = void 0;
		this.config = null;
		this.callbacks = null;
		this.context = null;
		this.loader = null;
		this.stats = void 0;
		this.xhrSetup = config ? config.xhrSetup || null : null;
		this.stats = new LoadStats();
		this.retryDelay = 0;
	}
	destroy() {
		this.callbacks = null;
		this.abortInternal();
		this.loader = null;
		this.config = null;
		this.context = null;
		this.xhrSetup = null;
	}
	abortInternal() {
		const loader = this.loader;
		self.clearTimeout(this.requestTimeout);
		self.clearTimeout(this.retryTimeout);
		if (loader) {
			loader.onreadystatechange = null;
			loader.onprogress = null;
			if (loader.readyState !== 4) {
				this.stats.aborted = true;
				loader.abort();
			}
		}
	}
	abort() {
		var _this$callbacks;
		this.abortInternal();
		if ((_this$callbacks = this.callbacks) != null && _this$callbacks.onAbort) this.callbacks.onAbort(this.stats, this.context, this.loader);
	}
	load(context, config, callbacks) {
		if (this.stats.loading.start) throw new Error("Loader can only be used once.");
		this.stats.loading.start = self.performance.now();
		this.context = context;
		this.config = config;
		this.callbacks = callbacks;
		this.loadInternal();
	}
	loadInternal() {
		const { config, context } = this;
		if (!config || !context) return;
		const xhr = this.loader = new self.XMLHttpRequest();
		const stats = this.stats;
		stats.loading.first = 0;
		stats.loaded = 0;
		stats.aborted = false;
		const xhrSetup = this.xhrSetup;
		if (xhrSetup) Promise.resolve().then(() => {
			if (this.loader !== xhr || this.stats.aborted) return;
			return xhrSetup(xhr, context.url);
		}).catch((error) => {
			if (this.loader !== xhr || this.stats.aborted) return;
			xhr.open("GET", context.url, true);
			return xhrSetup(xhr, context.url);
		}).then(() => {
			if (this.loader !== xhr || this.stats.aborted) return;
			this.openAndSendXhr(xhr, context, config);
		}).catch((error) => {
			var _this$callbacks2;
			(_this$callbacks2 = this.callbacks) == null || _this$callbacks2.onError({
				code: xhr.status,
				text: error.message
			}, context, xhr, stats);
		});
		else this.openAndSendXhr(xhr, context, config);
	}
	openAndSendXhr(xhr, context, config) {
		if (!xhr.readyState) xhr.open("GET", context.url, true);
		const headers = context.headers;
		const { maxTimeToFirstByteMs, maxLoadTimeMs } = config.loadPolicy;
		if (headers) for (const header in headers) xhr.setRequestHeader(header, headers[header]);
		if (context.rangeEnd) xhr.setRequestHeader("Range", "bytes=" + context.rangeStart + "-" + (context.rangeEnd - 1));
		xhr.onreadystatechange = this.readystatechange.bind(this);
		xhr.onprogress = this.loadprogress.bind(this);
		xhr.responseType = context.responseType;
		self.clearTimeout(this.requestTimeout);
		config.timeout = maxTimeToFirstByteMs && isFiniteNumber(maxTimeToFirstByteMs) ? maxTimeToFirstByteMs : maxLoadTimeMs;
		this.requestTimeout = self.setTimeout(this.loadtimeout.bind(this), config.timeout);
		xhr.send();
	}
	readystatechange() {
		const { context, loader: xhr, stats } = this;
		if (!context || !xhr) return;
		const readyState = xhr.readyState;
		const config = this.config;
		if (stats.aborted) return;
		if (readyState >= 2) {
			if (stats.loading.first === 0) {
				stats.loading.first = Math.max(self.performance.now(), stats.loading.start);
				if (config.timeout !== config.loadPolicy.maxLoadTimeMs) {
					self.clearTimeout(this.requestTimeout);
					config.timeout = config.loadPolicy.maxLoadTimeMs;
					this.requestTimeout = self.setTimeout(this.loadtimeout.bind(this), config.loadPolicy.maxLoadTimeMs - (stats.loading.first - stats.loading.start));
				}
			}
			if (readyState === 4) {
				self.clearTimeout(this.requestTimeout);
				xhr.onreadystatechange = null;
				xhr.onprogress = null;
				const status = xhr.status;
				const useResponseText = xhr.responseType === "text" ? xhr.responseText : null;
				if (status >= 200 && status < 300) {
					const data = useResponseText != null ? useResponseText : xhr.response;
					if (data != null) {
						var _this$callbacks3, _this$callbacks4;
						stats.loading.end = Math.max(self.performance.now(), stats.loading.first);
						stats.loaded = stats.total = xhr.responseType === "arraybuffer" ? data.byteLength : data.length;
						stats.bwEstimate = stats.total * 8e3 / (stats.loading.end - stats.loading.first);
						const onProgress = (_this$callbacks3 = this.callbacks) == null ? void 0 : _this$callbacks3.onProgress;
						if (onProgress) onProgress(stats, context, data, xhr);
						const _response = {
							url: xhr.responseURL,
							data,
							code: status
						};
						(_this$callbacks4 = this.callbacks) == null || _this$callbacks4.onSuccess(_response, stats, context, xhr);
						return;
					}
				}
				const retryConfig = config.loadPolicy.errorRetry;
				const retryCount = stats.retry;
				if (shouldRetry(retryConfig, retryCount, false, {
					url: context.url,
					data: void 0,
					code: status
				})) this.retry(retryConfig);
				else {
					var _this$callbacks5;
					logger.error(`${status} while loading ${context.url}`);
					(_this$callbacks5 = this.callbacks) == null || _this$callbacks5.onError({
						code: status,
						text: xhr.statusText
					}, context, xhr, stats);
				}
			}
		}
	}
	loadtimeout() {
		if (!this.config) return;
		const retryConfig = this.config.loadPolicy.timeoutRetry;
		const retryCount = this.stats.retry;
		if (shouldRetry(retryConfig, retryCount, true)) this.retry(retryConfig);
		else {
			var _this$context;
			logger.warn(`timeout while loading ${(_this$context = this.context) == null ? void 0 : _this$context.url}`);
			const callbacks = this.callbacks;
			if (callbacks) {
				this.abortInternal();
				callbacks.onTimeout(this.stats, this.context, this.loader);
			}
		}
	}
	retry(retryConfig) {
		const { context, stats } = this;
		this.retryDelay = getRetryDelay(retryConfig, stats.retry);
		stats.retry++;
		logger.warn(`${status ? "HTTP Status " + status : "Timeout"} while loading ${context == null ? void 0 : context.url}, retrying ${stats.retry}/${retryConfig.maxNumRetry} in ${this.retryDelay}ms`);
		this.abortInternal();
		this.loader = null;
		self.clearTimeout(this.retryTimeout);
		this.retryTimeout = self.setTimeout(this.loadInternal.bind(this), this.retryDelay);
	}
	loadprogress(event) {
		const stats = this.stats;
		stats.loaded = event.loaded;
		if (event.lengthComputable) stats.total = event.total;
	}
	getCacheAge() {
		let result = null;
		if (this.loader && AGE_HEADER_LINE_REGEX.test(this.loader.getAllResponseHeaders())) {
			const ageHeader = this.loader.getResponseHeader("age");
			result = ageHeader ? parseFloat(ageHeader) : null;
		}
		return result;
	}
	getResponseHeader(name) {
		if (this.loader && new RegExp(`^${name}:\\s*[\\d.]+\\s*$`, "im").test(this.loader.getAllResponseHeaders())) return this.loader.getResponseHeader(name);
		return null;
	}
};
/**
* @ignore
* If possible, keep hlsDefaultConfig shallow
* It is cloned whenever a new Hls instance is created, by keeping the config
* shallow the properties are cloned, and we don't end up manipulating the default
*/
var hlsDefaultConfig = _objectSpread2(_objectSpread2({
	autoStartLoad: true,
	startPosition: -1,
	defaultAudioCodec: void 0,
	debug: false,
	capLevelOnFPSDrop: false,
	capLevelToPlayerSize: false,
	ignoreDevicePixelRatio: false,
	maxDevicePixelRatio: Number.POSITIVE_INFINITY,
	preferManagedMediaSource: true,
	initialLiveManifestSize: 1,
	maxBufferLength: 30,
	backBufferLength: Infinity,
	frontBufferFlushThreshold: Infinity,
	startOnSegmentBoundary: false,
	maxBufferSize: 60 * 1e3 * 1e3,
	maxFragLookUpTolerance: .25,
	maxBufferHole: .1,
	detectStallWithCurrentTimeMs: 1250,
	highBufferWatchdogPeriod: 2,
	nudgeOffset: .1,
	nudgeMaxRetry: 3,
	nudgeOnVideoHole: true,
	liveSyncMode: "edge",
	liveSyncDurationCount: 3,
	liveSyncOnStallIncrease: 1,
	liveMaxLatencyDurationCount: Infinity,
	liveSyncDuration: void 0,
	liveMaxLatencyDuration: void 0,
	maxLiveSyncPlaybackRate: 1,
	liveDurationInfinity: false,
	/**
	* @deprecated use backBufferLength
	*/
	liveBackBufferLength: null,
	maxMaxBufferLength: 600,
	enableWorker: true,
	workerPath: null,
	enableSoftwareAES: true,
	startLevel: void 0,
	startFragPrefetch: false,
	fpsDroppedMonitoringPeriod: 5e3,
	fpsDroppedMonitoringThreshold: .2,
	appendErrorMaxRetry: 3,
	ignorePlaylistParsingErrors: false,
	loader: XhrLoader,
	fLoader: void 0,
	pLoader: void 0,
	xhrSetup: void 0,
	licenseXhrSetup: void 0,
	licenseResponseCallback: void 0,
	abrController: AbrController,
	bufferController: BufferController,
	capLevelController: CapLevelController,
	errorController: ErrorController,
	fpsController: FPSController,
	stretchShortVideoTrack: false,
	maxAudioFramesDrift: 1,
	forceKeyFrameOnDiscontinuity: true,
	abrEwmaFastLive: 3,
	abrEwmaSlowLive: 9,
	abrEwmaFastVoD: 3,
	abrEwmaSlowVoD: 9,
	abrEwmaDefaultEstimate: 5e5,
	abrEwmaDefaultEstimateMax: 5e6,
	abrBandWidthFactor: .95,
	abrBandWidthUpFactor: .7,
	abrMaxWithRealBitrate: false,
	maxStarvationDelay: 4,
	maxLoadingDelay: 4,
	minAutoBitrate: 0,
	emeEnabled: false,
	widevineLicenseUrl: void 0,
	drmSystems: {},
	drmSystemOptions: {},
	requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess,
	requireKeySystemAccessOnStart: false,
	testBandwidth: true,
	progressive: false,
	lowLatencyMode: true,
	cmcd: void 0,
	enableDateRangeMetadataCues: true,
	enableEmsgMetadataCues: true,
	enableEmsgKLVMetadata: false,
	enableID3MetadataCues: true,
	enableInterstitialPlayback: true,
	interstitialAppendInPlace: true,
	interstitialLiveLookAhead: 10,
	useMediaCapabilities: true,
	preserveManualLevelOnError: false,
	certLoadPolicy: { default: {
		maxTimeToFirstByteMs: 8e3,
		maxLoadTimeMs: 2e4,
		timeoutRetry: null,
		errorRetry: null
	} },
	keyLoadPolicy: { default: {
		maxTimeToFirstByteMs: 8e3,
		maxLoadTimeMs: 2e4,
		timeoutRetry: {
			maxNumRetry: 1,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 2e4,
			backoff: "linear"
		},
		errorRetry: {
			maxNumRetry: 8,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 2e4,
			backoff: "linear"
		}
	} },
	manifestLoadPolicy: { default: {
		maxTimeToFirstByteMs: Infinity,
		maxLoadTimeMs: 2e4,
		timeoutRetry: {
			maxNumRetry: 2,
			retryDelayMs: 0,
			maxRetryDelayMs: 0
		},
		errorRetry: {
			maxNumRetry: 1,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 8e3
		}
	} },
	playlistLoadPolicy: { default: {
		maxTimeToFirstByteMs: 1e4,
		maxLoadTimeMs: 2e4,
		timeoutRetry: {
			maxNumRetry: 2,
			retryDelayMs: 0,
			maxRetryDelayMs: 0
		},
		errorRetry: {
			maxNumRetry: 2,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 8e3
		}
	} },
	fragLoadPolicy: { default: {
		maxTimeToFirstByteMs: 1e4,
		maxLoadTimeMs: 12e4,
		timeoutRetry: {
			maxNumRetry: 4,
			retryDelayMs: 0,
			maxRetryDelayMs: 0
		},
		errorRetry: {
			maxNumRetry: 6,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 8e3
		}
	} },
	steeringManifestLoadPolicy: { default: {
		maxTimeToFirstByteMs: 1e4,
		maxLoadTimeMs: 2e4,
		timeoutRetry: {
			maxNumRetry: 2,
			retryDelayMs: 0,
			maxRetryDelayMs: 0
		},
		errorRetry: {
			maxNumRetry: 1,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 8e3
		}
	} },
	interstitialAssetListLoadPolicy: { default: {
		maxTimeToFirstByteMs: 1e4,
		maxLoadTimeMs: 3e4,
		timeoutRetry: {
			maxNumRetry: 0,
			retryDelayMs: 0,
			maxRetryDelayMs: 0
		},
		errorRetry: {
			maxNumRetry: 0,
			retryDelayMs: 1e3,
			maxRetryDelayMs: 8e3
		}
	} },
	manifestLoadingTimeOut: 1e4,
	manifestLoadingMaxRetry: 1,
	manifestLoadingRetryDelay: 1e3,
	manifestLoadingMaxRetryTimeout: 64e3,
	levelLoadingTimeOut: 1e4,
	levelLoadingMaxRetry: 4,
	levelLoadingRetryDelay: 1e3,
	levelLoadingMaxRetryTimeout: 64e3,
	fragLoadingTimeOut: 2e4,
	fragLoadingMaxRetry: 6,
	fragLoadingRetryDelay: 1e3,
	fragLoadingMaxRetryTimeout: 64e3
}, timelineConfig()), {}, {
	subtitleStreamController: SubtitleStreamController,
	subtitleTrackController: SubtitleTrackController,
	timelineController: TimelineController,
	audioStreamController: AudioStreamController,
	audioTrackController: AudioTrackController,
	emeController: EMEController,
	cmcdController: CMCDController,
	contentSteeringController: ContentSteeringController,
	interstitialsController: InterstitialsController
});
function timelineConfig() {
	return {
		cueHandler: Cues,
		enableWebVTT: true,
		enableIMSC1: true,
		enableCEA708Captions: true,
		captionsTextTrack1Label: "English",
		captionsTextTrack1LanguageCode: "en",
		captionsTextTrack2Label: "Spanish",
		captionsTextTrack2LanguageCode: "es",
		captionsTextTrack3Label: "Unknown CC",
		captionsTextTrack3LanguageCode: "",
		captionsTextTrack4Label: "Unknown CC",
		captionsTextTrack4LanguageCode: "",
		renderTextTracksNatively: true
	};
}
/**
* @ignore
*/
function mergeConfig(defaultConfig, userConfig, logger) {
	if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
	if (userConfig.liveMaxLatencyDurationCount !== void 0 && (userConfig.liveSyncDurationCount === void 0 || userConfig.liveMaxLatencyDurationCount <= userConfig.liveSyncDurationCount)) throw new Error("Illegal hls.js config: \"liveMaxLatencyDurationCount\" must be greater than \"liveSyncDurationCount\"");
	if (userConfig.liveMaxLatencyDuration !== void 0 && (userConfig.liveSyncDuration === void 0 || userConfig.liveMaxLatencyDuration <= userConfig.liveSyncDuration)) throw new Error("Illegal hls.js config: \"liveMaxLatencyDuration\" must be greater than \"liveSyncDuration\"");
	const defaultsCopy = deepCpy(defaultConfig);
	const deprecatedSettingTypes = [
		"manifest",
		"level",
		"frag"
	];
	const deprecatedSettings = [
		"TimeOut",
		"MaxRetry",
		"RetryDelay",
		"MaxRetryTimeout"
	];
	deprecatedSettingTypes.forEach((type) => {
		const policyName = `${type === "level" ? "playlist" : type}LoadPolicy`;
		const policyNotSet = userConfig[policyName] === void 0;
		const report = [];
		deprecatedSettings.forEach((setting) => {
			const deprecatedSetting = `${type}Loading${setting}`;
			const value = userConfig[deprecatedSetting];
			if (value !== void 0 && policyNotSet) {
				report.push(deprecatedSetting);
				const settings = defaultsCopy[policyName].default;
				userConfig[policyName] = { default: settings };
				switch (setting) {
					case "TimeOut":
						settings.maxLoadTimeMs = value;
						settings.maxTimeToFirstByteMs = value;
						break;
					case "MaxRetry":
						settings.errorRetry.maxNumRetry = value;
						settings.timeoutRetry.maxNumRetry = value;
						break;
					case "RetryDelay":
						settings.errorRetry.retryDelayMs = value;
						settings.timeoutRetry.retryDelayMs = value;
						break;
					case "MaxRetryTimeout":
						settings.errorRetry.maxRetryDelayMs = value;
						settings.timeoutRetry.maxRetryDelayMs = value;
						break;
				}
			}
		});
		if (report.length) logger.warn(`hls.js config: "${report.join("\", \"")}" setting(s) are deprecated, use "${policyName}": ${stringify(userConfig[policyName])}`);
	});
	return _objectSpread2(_objectSpread2({}, defaultsCopy), userConfig);
}
function deepCpy(obj) {
	if (obj && typeof obj === "object") {
		if (Array.isArray(obj)) return obj.map(deepCpy);
		return Object.keys(obj).reduce((result, key) => {
			result[key] = deepCpy(obj[key]);
			return result;
		}, {});
	}
	return obj;
}
/**
* @ignore
*/
function enableStreamingMode(config, logger) {
	const currentLoader = config.loader;
	if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
		logger.log("[config]: Custom loader detected, cannot enable progressive streaming");
		config.progressive = false;
	} else if (fetchSupported()) {
		config.loader = FetchLoader;
		config.progressive = true;
		config.enableSoftwareAES = true;
		logger.log("[config]: Progressive streaming enabled, using FetchLoader");
	}
}
var MAX_START_GAP_JUMP = 2;
var SKIP_BUFFER_HOLE_STEP_SECONDS = .1;
var SKIP_BUFFER_RANGE_START = .05;
var TICK_INTERVAL$1 = 100;
var GapController = class extends TaskLoop {
	constructor(hls, fragmentTracker) {
		super("gap-controller", hls.logger);
		this.hls = void 0;
		this.fragmentTracker = void 0;
		this.media = null;
		this.mediaSource = void 0;
		this.nudgeRetry = 0;
		this.stallReported = false;
		this.stalled = null;
		this.moved = false;
		this.seeking = false;
		this.buffered = {};
		this.lastCurrentTime = 0;
		this.ended = 0;
		this.waiting = 0;
		this.onMediaPlaying = () => {
			this.ended = 0;
			this.waiting = 0;
		};
		this.onMediaWaiting = () => {
			var _this$media;
			if ((_this$media = this.media) != null && _this$media.seeking) return;
			this.waiting = self.performance.now();
			this.tick();
		};
		this.onMediaEnded = () => {
			if (this.hls) {
				var _this$media2;
				this.ended = ((_this$media2 = this.media) == null ? void 0 : _this$media2.currentTime) || 1;
				this.hls.trigger(Events.MEDIA_ENDED, { stalled: false });
			}
		};
		this.hls = hls;
		this.fragmentTracker = fragmentTracker;
		this.registerListeners();
	}
	registerListeners() {
		const { hls } = this;
		if (hls) {
			hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this);
		}
	}
	unregisterListeners() {
		const { hls } = this;
		if (hls) {
			hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this);
		}
	}
	destroy() {
		super.destroy();
		this.unregisterListeners();
		this.media = this.hls = this.fragmentTracker = null;
		this.mediaSource = void 0;
	}
	onMediaAttached(event, data) {
		this.setInterval(TICK_INTERVAL$1);
		this.mediaSource = data.mediaSource;
		const media = this.media = data.media;
		addEventListener(media, "playing", this.onMediaPlaying);
		addEventListener(media, "waiting", this.onMediaWaiting);
		addEventListener(media, "ended", this.onMediaEnded);
	}
	onMediaDetaching(event, data) {
		this.clearInterval();
		const { media } = this;
		if (media) {
			removeEventListener(media, "playing", this.onMediaPlaying);
			removeEventListener(media, "waiting", this.onMediaWaiting);
			removeEventListener(media, "ended", this.onMediaEnded);
			this.media = null;
		}
		this.mediaSource = void 0;
	}
	onBufferAppended(event, data) {
		this.buffered = data.timeRanges;
	}
	get hasBuffered() {
		return Object.keys(this.buffered).length > 0;
	}
	tick() {
		var _this$media3;
		if (!((_this$media3 = this.media) != null && _this$media3.readyState) || !this.hasBuffered) return;
		const currentTime = this.media.currentTime;
		this.poll(currentTime, this.lastCurrentTime);
		this.lastCurrentTime = currentTime;
	}
	/**
	* Checks if the playhead is stuck within a gap, and if so, attempts to free it.
	* A gap is an unbuffered range between two buffered ranges (or the start and the first buffered range).
	*
	* @param lastCurrentTime - Previously read playhead position
	*/
	poll(currentTime, lastCurrentTime) {
		var _this$hls, _this$hls2;
		const config = (_this$hls = this.hls) == null ? void 0 : _this$hls.config;
		if (!config) return;
		const media = this.media;
		if (!media) return;
		const { seeking } = media;
		const seeked = this.seeking && !seeking;
		const beginSeek = !this.seeking && seeking;
		const pausedEndedOrHalted = media.paused && !seeking || media.ended || media.playbackRate === 0;
		this.seeking = seeking;
		if (currentTime !== lastCurrentTime) {
			if (lastCurrentTime) this.ended = 0;
			this.moved = true;
			if (!seeking) {
				this.nudgeRetry = 0;
				if (config.nudgeOnVideoHole && !pausedEndedOrHalted && currentTime > lastCurrentTime) this.nudgeOnVideoHole(currentTime, lastCurrentTime);
			}
			if (this.waiting === 0) this.stallResolved(currentTime);
			return;
		}
		if (beginSeek || seeked) {
			if (seeked) this.stallResolved(currentTime);
			return;
		}
		if (pausedEndedOrHalted) {
			this.nudgeRetry = 0;
			this.stallResolved(currentTime);
			if (!this.ended && media.ended && this.hls) {
				this.ended = currentTime || 1;
				this.hls.trigger(Events.MEDIA_ENDED, { stalled: false });
			}
			return;
		}
		if (!BufferHelper.getBuffered(media).length) {
			this.nudgeRetry = 0;
			return;
		}
		const bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
		const nextStart = bufferInfo.nextStart || 0;
		const fragmentTracker = this.fragmentTracker;
		if (seeking && fragmentTracker && this.hls) {
			const inFlightDependency = getInFlightDependency(this.hls.inFlightFragments, currentTime);
			const hasEnoughBuffer = bufferInfo.len > MAX_START_GAP_JUMP;
			const noBufferHole = !nextStart || inFlightDependency || nextStart - currentTime > MAX_START_GAP_JUMP && !fragmentTracker.getPartialFragment(currentTime);
			if (hasEnoughBuffer || noBufferHole) return;
			this.moved = false;
		}
		const levelDetails = (_this$hls2 = this.hls) == null ? void 0 : _this$hls2.latestLevelDetails;
		if (!this.moved && this.stalled !== null && fragmentTracker) {
			if (!(bufferInfo.len > 0) && !nextStart) return;
			const startJump = Math.max(nextStart, bufferInfo.start || 0) - currentTime;
			const maxStartGapJump = !!(levelDetails != null && levelDetails.live) ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
			const appended = appendedFragAtPosition(currentTime, fragmentTracker);
			if (startJump > 0 && (startJump <= maxStartGapJump || appended)) {
				if (!media.paused) this._trySkipBufferHole(appended);
				return;
			}
		}
		const detectStallWithCurrentTimeMs = config.detectStallWithCurrentTimeMs;
		const tnow = self.performance.now();
		const tWaiting = this.waiting;
		let stalled = this.stalled;
		if (stalled === null) if (tWaiting > 0 && tnow - tWaiting < detectStallWithCurrentTimeMs) stalled = this.stalled = tWaiting;
		else {
			this.stalled = tnow;
			return;
		}
		const stalledDuration = tnow - stalled;
		if (!seeking && (stalledDuration >= detectStallWithCurrentTimeMs || tWaiting) && this.hls) {
			var _this$mediaSource;
			if (((_this$mediaSource = this.mediaSource) == null ? void 0 : _this$mediaSource.readyState) === "ended" && !(levelDetails != null && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
				if (this.ended) return;
				this.ended = currentTime || 1;
				this.hls.trigger(Events.MEDIA_ENDED, { stalled: true });
				return;
			}
			this._reportStall(bufferInfo);
			if (!this.media || !this.hls) return;
		}
		const bufferedWithHoles = BufferHelper.bufferInfo(media, currentTime, config.maxBufferHole);
		this._tryFixBufferStall(bufferedWithHoles, stalledDuration, currentTime);
	}
	stallResolved(currentTime) {
		const stalled = this.stalled;
		if (stalled && this.hls) {
			this.stalled = null;
			if (this.stallReported) {
				const stalledDuration = self.performance.now() - stalled;
				this.log(`playback not stuck anymore @${currentTime}, after ${Math.round(stalledDuration)}ms`);
				this.stallReported = false;
				this.waiting = 0;
				this.hls.trigger(Events.STALL_RESOLVED, {});
			}
		}
	}
	nudgeOnVideoHole(currentTime, lastCurrentTime) {
		var _this$buffered$audio;
		const videoSourceBuffered = this.buffered.video;
		if (this.hls && this.media && this.fragmentTracker && (_this$buffered$audio = this.buffered.audio) != null && _this$buffered$audio.length && videoSourceBuffered && videoSourceBuffered.length > 1 && currentTime > videoSourceBuffered.end(0)) {
			const audioBufferInfo = BufferHelper.bufferedInfo(BufferHelper.timeRangesToArray(this.buffered.audio), currentTime, 0);
			if (audioBufferInfo.len > 1 && lastCurrentTime >= audioBufferInfo.start) {
				const videoTimes = BufferHelper.timeRangesToArray(videoSourceBuffered);
				const lastBufferedIndex = BufferHelper.bufferedInfo(videoTimes, lastCurrentTime, 0).bufferedIndex;
				if (lastBufferedIndex > -1 && lastBufferedIndex < videoTimes.length - 1) {
					const bufferedIndex = BufferHelper.bufferedInfo(videoTimes, currentTime, 0).bufferedIndex;
					const holeStart = videoTimes[lastBufferedIndex].end;
					const holeEnd = videoTimes[lastBufferedIndex + 1].start;
					if ((bufferedIndex === -1 || bufferedIndex > lastBufferedIndex) && holeEnd - holeStart < 1 && currentTime - holeStart < 2) {
						const error = /* @__PURE__ */ new Error(`nudging playhead to flush pipeline after video hole. currentTime: ${currentTime} hole: ${holeStart} -> ${holeEnd} buffered index: ${bufferedIndex}`);
						this.warn(error.message);
						this.media.currentTime += 1e-6;
						let frag = appendedFragAtPosition(currentTime, this.fragmentTracker);
						if (frag && "fragment" in frag) frag = frag.fragment;
						else if (!frag) frag = void 0;
						const bufferInfo = BufferHelper.bufferInfo(this.media, currentTime, 0);
						this.hls.trigger(Events.ERROR, {
							type: ErrorTypes.MEDIA_ERROR,
							details: ErrorDetails.BUFFER_SEEK_OVER_HOLE,
							fatal: false,
							error,
							reason: error.message,
							frag,
							buffer: bufferInfo.len,
							bufferInfo
						});
					}
				}
			}
		}
	}
	/**
	* Detects and attempts to fix known buffer stalling issues.
	* @param bufferInfo - The properties of the current buffer.
	* @param stalledDurationMs - The amount of time Hls.js has been stalling for.
	* @private
	*/
	_tryFixBufferStall(bufferInfo, stalledDurationMs, currentTime) {
		var _this$hls3, _this$hls4;
		const { fragmentTracker, media } = this;
		const config = (_this$hls3 = this.hls) == null ? void 0 : _this$hls3.config;
		if (!media || !fragmentTracker || !config) return;
		const levelDetails = (_this$hls4 = this.hls) == null ? void 0 : _this$hls4.latestLevelDetails;
		const appended = appendedFragAtPosition(currentTime, fragmentTracker);
		if (appended || levelDetails != null && levelDetails.live && currentTime < levelDetails.fragmentStart) {
			if (this._trySkipBufferHole(appended) || !this.media) return;
		}
		const bufferedRanges = bufferInfo.buffered;
		const adjacentTraversal = this.adjacentTraversal(bufferInfo, currentTime);
		if ((bufferedRanges && bufferedRanges.length > 1 && bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && (bufferInfo.nextStart - currentTime < config.maxBufferHole || adjacentTraversal)) && (stalledDurationMs > config.highBufferWatchdogPeriod * 1e3 || this.waiting)) {
			this.warn("Trying to nudge playhead over buffer-hole");
			this._tryNudgeBuffer(bufferInfo);
		}
	}
	adjacentTraversal(bufferInfo, currentTime) {
		const fragmentTracker = this.fragmentTracker;
		const nextStart = bufferInfo.nextStart;
		if (fragmentTracker && nextStart) {
			const current = fragmentTracker.getFragAtPos(currentTime, PlaylistLevelType.MAIN);
			const next = fragmentTracker.getFragAtPos(nextStart, PlaylistLevelType.MAIN);
			if (current && next) return next.sn - current.sn < 2;
		}
		return false;
	}
	/**
	* Triggers a BUFFER_STALLED_ERROR event, but only once per stall period.
	* @param bufferLen - The playhead distance from the end of the current buffer segment.
	* @private
	*/
	_reportStall(bufferInfo) {
		const { hls, media, stallReported, stalled } = this;
		if (!stallReported && stalled !== null && media && hls) {
			this.stallReported = true;
			const error = /* @__PURE__ */ new Error(`Playback stalling at @${media.currentTime} due to low buffer (${stringify(bufferInfo)})`);
			this.warn(error.message);
			hls.trigger(Events.ERROR, {
				type: ErrorTypes.MEDIA_ERROR,
				details: ErrorDetails.BUFFER_STALLED_ERROR,
				fatal: false,
				error,
				buffer: bufferInfo.len,
				bufferInfo,
				stalled: { start: stalled }
			});
		}
	}
	/**
	* Attempts to fix buffer stalls by jumping over known gaps caused by partial fragments
	* @param appended - The fragment or part found at the current time (where playback is stalling).
	* @private
	*/
	_trySkipBufferHole(appended) {
		var _this$hls5;
		const { fragmentTracker, media } = this;
		const config = (_this$hls5 = this.hls) == null ? void 0 : _this$hls5.config;
		if (!media || !fragmentTracker || !config) return 0;
		const currentTime = media.currentTime;
		const bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
		const startTime = currentTime < bufferInfo.start ? bufferInfo.start : bufferInfo.nextStart;
		if (startTime && this.hls) {
			const bufferStarved = bufferInfo.len <= config.maxBufferHole;
			const waiting = bufferInfo.len > 0 && bufferInfo.len < 1 && media.readyState < 3;
			const gapLength = startTime - currentTime;
			if (gapLength > 0 && (bufferStarved || waiting)) {
				if (gapLength > config.maxBufferHole) {
					let startGap = false;
					if (currentTime === 0) {
						const startFrag = fragmentTracker.getAppendedFrag(0, PlaylistLevelType.MAIN);
						if (startFrag && startTime < startFrag.end) startGap = true;
					}
					if (!startGap && appended) {
						var _this$hls$loadLevelOb;
						if (!((_this$hls$loadLevelOb = this.hls.loadLevelObj) != null && _this$hls$loadLevelOb.details)) return 0;
						if (getInFlightDependency(this.hls.inFlightFragments, startTime)) return 0;
						let moreToLoad = false;
						let pos = appended.end;
						while (pos < startTime) {
							const provisioned = appendedFragAtPosition(pos, fragmentTracker);
							if (provisioned) pos += provisioned.duration;
							else {
								moreToLoad = true;
								break;
							}
						}
						if (moreToLoad) return 0;
					}
				}
				const targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
				this.warn(`skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`);
				this.moved = true;
				media.currentTime = targetTime;
				if (!(appended != null && appended.gap)) {
					const error = /* @__PURE__ */ new Error(`fragment loaded with buffer holes, seeking from ${currentTime} to ${targetTime}`);
					const errorData = {
						type: ErrorTypes.MEDIA_ERROR,
						details: ErrorDetails.BUFFER_SEEK_OVER_HOLE,
						fatal: false,
						error,
						reason: error.message,
						buffer: bufferInfo.len,
						bufferInfo
					};
					if (appended) if ("fragment" in appended) errorData.part = appended;
					else errorData.frag = appended;
					this.hls.trigger(Events.ERROR, errorData);
				}
				return targetTime;
			}
		}
		return 0;
	}
	/**
	* Attempts to fix buffer stalls by advancing the mediaElement's current time by a small amount.
	* @private
	*/
	_tryNudgeBuffer(bufferInfo) {
		const { hls, media, nudgeRetry } = this;
		const config = hls == null ? void 0 : hls.config;
		if (!media || !config) return 0;
		const currentTime = media.currentTime;
		this.nudgeRetry++;
		if (nudgeRetry < config.nudgeMaxRetry) {
			const targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
			const error = /* @__PURE__ */ new Error(`Nudging 'currentTime' from ${currentTime} to ${targetTime}`);
			this.warn(error.message);
			media.currentTime = targetTime;
			hls.trigger(Events.ERROR, {
				type: ErrorTypes.MEDIA_ERROR,
				details: ErrorDetails.BUFFER_NUDGE_ON_STALL,
				error,
				fatal: false,
				buffer: bufferInfo.len,
				bufferInfo
			});
		} else {
			const error = /* @__PURE__ */ new Error(`Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`);
			this.error(error.message);
			hls.trigger(Events.ERROR, {
				type: ErrorTypes.MEDIA_ERROR,
				details: ErrorDetails.BUFFER_STALLED_ERROR,
				error,
				fatal: true,
				buffer: bufferInfo.len,
				bufferInfo
			});
		}
	}
};
function getInFlightDependency(inFlightFragments, currentTime) {
	const main = inFlight(inFlightFragments.main);
	if (main && main.start <= currentTime) return main;
	const audio = inFlight(inFlightFragments.audio);
	if (audio && audio.start <= currentTime) return audio;
	return null;
}
function inFlight(inFlightData) {
	if (!inFlightData) return null;
	switch (inFlightData.state) {
		case State.IDLE:
		case State.STOPPED:
		case State.ENDED:
		case State.ERROR: return null;
	}
	return inFlightData.frag;
}
function appendedFragAtPosition(pos, fragmentTracker) {
	return fragmentTracker.getAppendedFrag(pos, PlaylistLevelType.MAIN) || fragmentTracker.getPartialFragment(pos);
}
var MIN_CUE_DURATION = .25;
function getCueClass() {
	if (typeof self === "undefined") return void 0;
	return self.VTTCue || self.TextTrackCue;
}
function createCueWithDataFields(Cue, startTime, endTime, data, type) {
	let cue = new Cue(startTime, endTime, "");
	try {
		cue.value = data;
		if (type) cue.type = type;
	} catch (e) {
		cue = new Cue(startTime, endTime, stringify(type ? _objectSpread2({ type }, data) : data));
	}
	return cue;
}
var MAX_CUE_ENDTIME = (() => {
	const Cue = getCueClass();
	try {
		Cue && new Cue(0, Number.POSITIVE_INFINITY, "");
	} catch (e) {
		return Number.MAX_VALUE;
	}
	return Number.POSITIVE_INFINITY;
})();
var ID3TrackController = class {
	constructor(hls) {
		this.hls = void 0;
		this.id3Track = null;
		this.media = null;
		this.dateRangeCuesAppended = {};
		this.removeCues = true;
		this.assetCue = void 0;
		this.onEventCueEnter = () => {
			if (!this.hls) return;
			this.hls.trigger(Events.EVENT_CUE_ENTER, {});
		};
		this.hls = hls;
		this._registerListeners();
	}
	destroy() {
		this._unregisterListeners();
		this.id3Track = null;
		this.media = null;
		this.dateRangeCuesAppended = {};
		this.hls = this.onEventCueEnter = null;
	}
	_registerListeners() {
		const { hls } = this;
		if (hls) {
			hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
			hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
			hls.on(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
			hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
			hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
			hls.on(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
		}
	}
	_unregisterListeners() {
		const { hls } = this;
		if (hls) {
			hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
			hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
			hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
			hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
			hls.off(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
			hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
			hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
			hls.off(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
		}
	}
	onMediaAttaching(event, data) {
		var _data$overrides;
		this.media = data.media;
		if (((_data$overrides = data.overrides) == null ? void 0 : _data$overrides.cueRemoval) === false) this.removeCues = false;
	}
	onMediaAttached() {
		var _this$hls;
		const details = (_this$hls = this.hls) == null ? void 0 : _this$hls.latestLevelDetails;
		if (details) this.updateDateRangeCues(details);
	}
	onMediaDetaching(event, data) {
		this.media = null;
		if (!!data.transferMedia) return;
		if (this.id3Track) {
			if (this.removeCues) clearCurrentCues(this.id3Track, this.onEventCueEnter);
			this.id3Track = null;
		}
		this.dateRangeCuesAppended = {};
	}
	onManifestLoading() {
		this.dateRangeCuesAppended = {};
	}
	createTrack(media) {
		const track = this.getID3Track(media.textTracks);
		track.mode = "hidden";
		return track;
	}
	getID3Track(textTracks) {
		if (!this.media) return;
		for (let i = 0; i < textTracks.length; i++) {
			const textTrack = textTracks[i];
			if (textTrack.kind === "metadata" && textTrack.label === "id3") {
				sendAddTrackEvent(textTrack, this.media);
				return textTrack;
			}
		}
		return this.media.addTextTrack("metadata", "id3");
	}
	onFragParsingMetadata(event, data) {
		if (!this.media || !this.hls) return;
		const { enableEmsgMetadataCues, enableID3MetadataCues } = this.hls.config;
		if (!enableEmsgMetadataCues && !enableID3MetadataCues) return;
		const { samples } = data;
		if (!this.id3Track) this.id3Track = this.createTrack(this.media);
		const Cue = getCueClass();
		if (!Cue) return;
		for (let i = 0; i < samples.length; i++) {
			const type = samples[i].type;
			if (type === MetadataSchema.emsg && !enableEmsgMetadataCues || !enableID3MetadataCues) continue;
			const frames = getId3Frames(samples[i].data);
			const startTime = samples[i].pts;
			let endTime = startTime + samples[i].duration;
			if (endTime > MAX_CUE_ENDTIME) endTime = MAX_CUE_ENDTIME;
			if (endTime - startTime <= 0) endTime = startTime + MIN_CUE_DURATION;
			for (let j = 0; j < frames.length; j++) {
				const frame = frames[j];
				if (!isId3TimestampFrame(frame)) {
					this.updateId3CueEnds(startTime, type);
					const cue = createCueWithDataFields(Cue, startTime, endTime, frame, type);
					if (cue) this.id3Track.addCue(cue);
				}
			}
		}
	}
	updateId3CueEnds(startTime, type) {
		var _this$id3Track;
		const cues = (_this$id3Track = this.id3Track) == null ? void 0 : _this$id3Track.cues;
		if (cues) for (let i = cues.length; i--;) {
			const cue = cues[i];
			if (cue.type === type && cue.startTime < startTime && cue.endTime === MAX_CUE_ENDTIME) cue.endTime = startTime;
		}
	}
	onBufferFlushing(event, { startOffset, endOffset, type }) {
		const { id3Track, hls } = this;
		if (!hls) return;
		const { config: { enableEmsgMetadataCues, enableID3MetadataCues } } = hls;
		if (id3Track && (enableEmsgMetadataCues || enableID3MetadataCues)) {
			let predicate;
			if (type === "audio") predicate = (cue) => cue.type === MetadataSchema.audioId3 && enableID3MetadataCues;
			else if (type === "video") predicate = (cue) => cue.type === MetadataSchema.emsg && enableEmsgMetadataCues;
			else predicate = (cue) => cue.type === MetadataSchema.audioId3 && enableID3MetadataCues || cue.type === MetadataSchema.emsg && enableEmsgMetadataCues;
			removeCuesInRange(id3Track, startOffset, endOffset, predicate);
		}
	}
	onLevelUpdated(event, { details }) {
		this.updateDateRangeCues(details, true);
	}
	onLevelPtsUpdated(event, data) {
		if (Math.abs(data.drift) > .01) this.updateDateRangeCues(data.details);
	}
	updateDateRangeCues(details, removeOldCues) {
		if (!this.hls || !this.media) return;
		const { assetPlayerId, timelineOffset, enableDateRangeMetadataCues, interstitialsController } = this.hls.config;
		if (!enableDateRangeMetadataCues) return;
		const Cue = getCueClass();
		if (assetPlayerId && timelineOffset && !interstitialsController) {
			const { fragmentStart, fragmentEnd } = details;
			let cue = this.assetCue;
			if (cue) {
				cue.startTime = fragmentStart;
				cue.endTime = fragmentEnd;
			} else if (Cue) {
				cue = this.assetCue = createCueWithDataFields(Cue, fragmentStart, fragmentEnd, { assetPlayerId: this.hls.config.assetPlayerId }, "hlsjs.interstitial.asset");
				if (cue) {
					cue.id = assetPlayerId;
					this.id3Track || (this.id3Track = this.createTrack(this.media));
					this.id3Track.addCue(cue);
					cue.addEventListener("enter", this.onEventCueEnter);
				}
			}
		}
		if (!details.hasProgramDateTime) return;
		const { id3Track } = this;
		const { dateRanges } = details;
		const ids = Object.keys(dateRanges);
		let dateRangeCuesAppended = this.dateRangeCuesAppended;
		if (id3Track && removeOldCues) {
			var _id3Track$cues;
			if ((_id3Track$cues = id3Track.cues) != null && _id3Track$cues.length) {
				const idsToRemove = Object.keys(dateRangeCuesAppended).filter((id) => !ids.includes(id));
				for (let i = idsToRemove.length; i--;) {
					var _dateRangeCuesAppende;
					const id = idsToRemove[i];
					const cues = (_dateRangeCuesAppende = dateRangeCuesAppended[id]) == null ? void 0 : _dateRangeCuesAppende.cues;
					delete dateRangeCuesAppended[id];
					if (cues) Object.keys(cues).forEach((key) => {
						const cue = cues[key];
						if (cue) {
							cue.removeEventListener("enter", this.onEventCueEnter);
							try {
								id3Track.removeCue(cue);
							} catch (e) {}
						}
					});
				}
			} else dateRangeCuesAppended = this.dateRangeCuesAppended = {};
		}
		const lastFragment = details.fragments[details.fragments.length - 1];
		if (ids.length === 0 || !isFiniteNumber(lastFragment == null ? void 0 : lastFragment.programDateTime)) return;
		this.id3Track || (this.id3Track = this.createTrack(this.media));
		for (let i = 0; i < ids.length; i++) {
			const id = ids[i];
			const dateRange = dateRanges[id];
			const startTime = dateRange.startTime;
			const appendedDateRangeCues = dateRangeCuesAppended[id];
			const cues = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.cues) || {};
			let durationKnown = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.durationKnown) || false;
			let endTime = MAX_CUE_ENDTIME;
			const { duration, endDate } = dateRange;
			if (endDate && duration !== null) {
				endTime = startTime + duration;
				durationKnown = true;
			} else if (dateRange.endOnNext && !durationKnown) {
				const nextDateRangeWithSameClass = ids.reduce((candidateDateRange, id) => {
					if (id !== dateRange.id) {
						const otherDateRange = dateRanges[id];
						if (otherDateRange.class === dateRange.class && otherDateRange.startDate > dateRange.startDate && (!candidateDateRange || dateRange.startDate < candidateDateRange.startDate)) return otherDateRange;
					}
					return candidateDateRange;
				}, null);
				if (nextDateRangeWithSameClass) {
					endTime = nextDateRangeWithSameClass.startTime;
					durationKnown = true;
				}
			}
			const attributes = Object.keys(dateRange.attr);
			for (let j = 0; j < attributes.length; j++) {
				const key = attributes[j];
				if (!isDateRangeCueAttribute(key)) continue;
				const cue = cues[key];
				if (cue) {
					if (durationKnown && !(appendedDateRangeCues != null && appendedDateRangeCues.durationKnown)) cue.endTime = endTime;
					else if (Math.abs(cue.startTime - startTime) > .01) {
						cue.startTime = startTime;
						cue.endTime = endTime;
					}
				} else if (Cue) {
					let data = dateRange.attr[key];
					if (isSCTE35Attribute(key)) data = hexToArrayBuffer(data);
					const _cue = createCueWithDataFields(Cue, startTime, endTime, {
						key,
						data
					}, MetadataSchema.dateRange);
					if (_cue) {
						_cue.id = id;
						this.id3Track.addCue(_cue);
						cues[key] = _cue;
						if (interstitialsController) {
							if (key === "X-ASSET-LIST" || key === "X-ASSET-URL") _cue.addEventListener("enter", this.onEventCueEnter);
						}
					}
				}
			}
			dateRangeCuesAppended[id] = {
				cues,
				dateRange,
				durationKnown
			};
		}
	}
};
var LatencyController = class {
	constructor(hls) {
		this.hls = void 0;
		this.config = void 0;
		this.media = null;
		this.currentTime = 0;
		this.stallCount = 0;
		this._latency = null;
		this._targetLatencyUpdated = false;
		this.onTimeupdate = () => {
			const { media } = this;
			const levelDetails = this.levelDetails;
			if (!media || !levelDetails) return;
			this.currentTime = media.currentTime;
			const latency = this.computeLatency();
			if (latency === null) return;
			this._latency = latency;
			const { lowLatencyMode, maxLiveSyncPlaybackRate } = this.config;
			if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) return;
			const targetLatency = this.targetLatency;
			if (targetLatency === null) return;
			const distanceFromTarget = latency - targetLatency;
			if (distanceFromTarget < Math.min(this.maxLatency, targetLatency + levelDetails.targetduration) && distanceFromTarget > .05 && this.forwardBufferLength > 1) {
				const max = Math.min(2, Math.max(1, maxLiveSyncPlaybackRate));
				const rate = Math.round(2 / (1 + Math.exp(-.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
				const playbackRate = Math.min(max, Math.max(1, rate));
				this.changeMediaPlaybackRate(media, playbackRate);
			} else if (media.playbackRate !== 1 && media.playbackRate !== 0) this.changeMediaPlaybackRate(media, 1);
		};
		this.hls = hls;
		this.config = hls.config;
		this.registerListeners();
	}
	get levelDetails() {
		var _this$hls;
		return ((_this$hls = this.hls) == null ? void 0 : _this$hls.latestLevelDetails) || null;
	}
	get latency() {
		return this._latency || 0;
	}
	get maxLatency() {
		const { config } = this;
		if (config.liveMaxLatencyDuration !== void 0) return config.liveMaxLatencyDuration;
		const levelDetails = this.levelDetails;
		return levelDetails ? config.liveMaxLatencyDurationCount * levelDetails.targetduration : 0;
	}
	get targetLatency() {
		const levelDetails = this.levelDetails;
		if (levelDetails === null || this.hls === null) return null;
		const { holdBack, partHoldBack, targetduration } = levelDetails;
		const { liveSyncDuration, liveSyncDurationCount, lowLatencyMode } = this.config;
		const userConfig = this.hls.userConfig;
		let targetLatency = lowLatencyMode ? partHoldBack || holdBack : holdBack;
		if (this._targetLatencyUpdated || userConfig.liveSyncDuration || userConfig.liveSyncDurationCount || targetLatency === 0) targetLatency = liveSyncDuration !== void 0 ? liveSyncDuration : liveSyncDurationCount * targetduration;
		const maxLiveSyncOnStallIncrease = targetduration;
		return targetLatency + Math.min(this.stallCount * this.config.liveSyncOnStallIncrease, maxLiveSyncOnStallIncrease);
	}
	set targetLatency(latency) {
		this.stallCount = 0;
		this.config.liveSyncDuration = latency;
		this._targetLatencyUpdated = true;
	}
	get liveSyncPosition() {
		const liveEdge = this.estimateLiveEdge();
		const targetLatency = this.targetLatency;
		if (liveEdge === null || targetLatency === null) return null;
		const levelDetails = this.levelDetails;
		if (levelDetails === null) return null;
		const edge = levelDetails.edge;
		const syncPosition = liveEdge - targetLatency - this.edgeStalled;
		const min = edge - levelDetails.totalduration;
		const max = edge - (this.config.lowLatencyMode && levelDetails.partTarget || levelDetails.targetduration);
		return Math.min(Math.max(min, syncPosition), max);
	}
	get drift() {
		const levelDetails = this.levelDetails;
		if (levelDetails === null) return 1;
		return levelDetails.drift;
	}
	get edgeStalled() {
		const levelDetails = this.levelDetails;
		if (levelDetails === null) return 0;
		const maxLevelUpdateAge = (this.config.lowLatencyMode && levelDetails.partTarget || levelDetails.targetduration) * 3;
		return Math.max(levelDetails.age - maxLevelUpdateAge, 0);
	}
	get forwardBufferLength() {
		const { media } = this;
		const levelDetails = this.levelDetails;
		if (!media || !levelDetails) return 0;
		const bufferedRanges = media.buffered.length;
		return (bufferedRanges ? media.buffered.end(bufferedRanges - 1) : levelDetails.edge) - this.currentTime;
	}
	destroy() {
		this.unregisterListeners();
		this.onMediaDetaching();
		this.hls = null;
	}
	registerListeners() {
		const { hls } = this;
		if (!hls) return;
		hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
		hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
		hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
		hls.on(Events.ERROR, this.onError, this);
	}
	unregisterListeners() {
		const { hls } = this;
		if (!hls) return;
		hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
		hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
		hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
		hls.off(Events.ERROR, this.onError, this);
	}
	onMediaAttached(event, data) {
		this.media = data.media;
		this.media.addEventListener("timeupdate", this.onTimeupdate);
	}
	onMediaDetaching() {
		if (this.media) {
			this.media.removeEventListener("timeupdate", this.onTimeupdate);
			this.media = null;
		}
	}
	onManifestLoading() {
		this._latency = null;
		this.stallCount = 0;
	}
	onLevelUpdated(event, { details }) {
		if (details.advanced) this.onTimeupdate();
		if (!details.live && this.media) this.media.removeEventListener("timeupdate", this.onTimeupdate);
	}
	onError(event, data) {
		var _this$levelDetails;
		if (data.details !== ErrorDetails.BUFFER_STALLED_ERROR) return;
		this.stallCount++;
		if (this.hls && (_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) this.hls.logger.warn("[latency-controller]: Stall detected, adjusting target latency");
	}
	changeMediaPlaybackRate(media, playbackRate) {
		var _this$hls2, _this$targetLatency;
		if (media.playbackRate === playbackRate) return;
		(_this$hls2 = this.hls) == null || _this$hls2.logger.debug(`[latency-controller]: latency=${this.latency.toFixed(3)}, targetLatency=${(_this$targetLatency = this.targetLatency) == null ? void 0 : _this$targetLatency.toFixed(3)}, forwardBufferLength=${this.forwardBufferLength.toFixed(3)}: adjusting playback rate from ${media.playbackRate} to ${playbackRate}`);
		media.playbackRate = playbackRate;
	}
	estimateLiveEdge() {
		const levelDetails = this.levelDetails;
		if (levelDetails === null) return null;
		return levelDetails.edge + levelDetails.age;
	}
	computeLatency() {
		const liveEdge = this.estimateLiveEdge();
		if (liveEdge === null) return null;
		return liveEdge - this.currentTime;
	}
};
var LevelController = class extends BasePlaylistController {
	constructor(hls, contentSteeringController) {
		super(hls, "level-controller");
		this._levels = [];
		this._firstLevel = -1;
		this._maxAutoLevel = -1;
		this._startLevel = void 0;
		this.currentLevel = null;
		this.currentLevelIndex = -1;
		this.manualLevelIndex = -1;
		this.steering = void 0;
		this.onParsedComplete = void 0;
		this.steering = contentSteeringController;
		this._registerListeners();
	}
	_registerListeners() {
		const { hls } = this;
		hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
		hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
		hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
		hls.on(Events.ERROR, this.onError, this);
	}
	_unregisterListeners() {
		const { hls } = this;
		hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
		hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
		hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
		hls.off(Events.ERROR, this.onError, this);
	}
	destroy() {
		this._unregisterListeners();
		this.steering = null;
		this.resetLevels();
		super.destroy();
	}
	stopLoad() {
		this._levels.forEach((level) => {
			level.loadError = 0;
			level.fragmentError = 0;
		});
		super.stopLoad();
	}
	resetLevels() {
		this._startLevel = void 0;
		this.manualLevelIndex = -1;
		this.currentLevelIndex = -1;
		this.currentLevel = null;
		this._levels = [];
		this._maxAutoLevel = -1;
	}
	onManifestLoading(event, data) {
		this.resetLevels();
	}
	onManifestLoaded(event, data) {
		const preferManagedMediaSource = this.hls.config.preferManagedMediaSource;
		const levels = [];
		const redundantSet = {};
		const generatePathwaySet = {};
		let resolutionFound = false;
		let videoCodecFound = false;
		let audioCodecFound = false;
		data.levels.forEach((levelParsed) => {
			const attributes = levelParsed.attrs;
			let { audioCodec, videoCodec } = levelParsed;
			if (audioCodec) levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || void 0;
			if (videoCodec) videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
			const { width, height, unknownCodecs } = levelParsed;
			const unknownUnsupportedCodecCount = (unknownCodecs == null ? void 0 : unknownCodecs.length) || 0;
			resolutionFound || (resolutionFound = !!(width && height));
			videoCodecFound || (videoCodecFound = !!videoCodec);
			audioCodecFound || (audioCodecFound = !!audioCodec);
			if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
				this.log(`Some or all CODECS not supported "${attributes.CODECS}"`);
				return;
			}
			const { CODECS, "FRAME-RATE": FRAMERATE, "HDCP-LEVEL": HDCP, "PATHWAY-ID": PATHWAY, RESOLUTION, "VIDEO-RANGE": VIDEO_RANGE } = attributes;
			const levelKey = `${`${PATHWAY || "."}-`}${levelParsed.bitrate}-${RESOLUTION}-${FRAMERATE}-${CODECS}-${VIDEO_RANGE}-${HDCP}`;
			if (!redundantSet[levelKey]) {
				const level = this.createLevel(levelParsed);
				redundantSet[levelKey] = level;
				generatePathwaySet[levelKey] = 1;
				levels.push(level);
			} else if (redundantSet[levelKey].uri !== levelParsed.url && !levelParsed.attrs["PATHWAY-ID"]) {
				const pathwayCount = generatePathwaySet[levelKey] += 1;
				levelParsed.attrs["PATHWAY-ID"] = new Array(pathwayCount + 1).join(".");
				const level = this.createLevel(levelParsed);
				redundantSet[levelKey] = level;
				levels.push(level);
			} else {
				redundantSet[levelKey].addGroupId("audio", attributes.AUDIO);
				redundantSet[levelKey].addGroupId("text", attributes.SUBTITLES);
			}
		});
		this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
	}
	createLevel(levelParsed) {
		const level = new Level(levelParsed);
		const supplemental = levelParsed.supplemental;
		if (supplemental != null && supplemental.videoCodec && !this.isVideoSupported(supplemental.videoCodec)) {
			const error = /* @__PURE__ */ new Error(`SUPPLEMENTAL-CODECS not supported "${supplemental.videoCodec}"`);
			this.log(error.message);
			level.supportedResult = getUnsupportedResult(error, []);
		}
		return level;
	}
	isAudioSupported(codec) {
		return areCodecsMediaSourceSupported(codec, "audio", this.hls.config.preferManagedMediaSource);
	}
	isVideoSupported(codec) {
		return areCodecsMediaSourceSupported(codec, "video", this.hls.config.preferManagedMediaSource);
	}
	filterAndSortMediaOptions(filteredLevels, data, resolutionFound, videoCodecFound, audioCodecFound) {
		var _data$stats;
		let audioTracks = [];
		let subtitleTracks = [];
		let levels = filteredLevels;
		const statsParsing = ((_data$stats = data.stats) == null ? void 0 : _data$stats.parsing) || {};
		if ((resolutionFound || videoCodecFound) && audioCodecFound) levels = levels.filter(({ videoCodec, videoRange, width, height }) => (!!videoCodec || !!(width && height)) && isVideoRange(videoRange));
		if (levels.length === 0) {
			Promise.resolve().then(() => {
				if (this.hls) {
					let message = "no level with compatible codecs found in manifest";
					let reason = message;
					if (data.levels.length) {
						reason = `one or more CODECS in variant not supported: ${stringify(data.levels.map((level) => level.attrs.CODECS).filter((value, index, array) => array.indexOf(value) === index))}`;
						this.warn(reason);
						message += ` (${reason})`;
					}
					const error = new Error(message);
					this.hls.trigger(Events.ERROR, {
						type: ErrorTypes.MEDIA_ERROR,
						details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR,
						fatal: true,
						url: data.url,
						error,
						reason
					});
				}
			});
			statsParsing.end = performance.now();
			return;
		}
		if (data.audioTracks) {
			audioTracks = data.audioTracks.filter((track) => !track.audioCodec || this.isAudioSupported(track.audioCodec));
			assignTrackIdsByGroup(audioTracks);
		}
		if (data.subtitles) {
			subtitleTracks = data.subtitles;
			assignTrackIdsByGroup(subtitleTracks);
		}
		const unsortedLevels = levels.slice(0);
		levels.sort((a, b) => {
			if (a.attrs["HDCP-LEVEL"] !== b.attrs["HDCP-LEVEL"]) return (a.attrs["HDCP-LEVEL"] || "") > (b.attrs["HDCP-LEVEL"] || "") ? 1 : -1;
			if (resolutionFound && a.height !== b.height) return a.height - b.height;
			if (a.frameRate !== b.frameRate) return a.frameRate - b.frameRate;
			if (a.videoRange !== b.videoRange) return VideoRangeValues.indexOf(a.videoRange) - VideoRangeValues.indexOf(b.videoRange);
			if (a.videoCodec !== b.videoCodec) {
				const valueA = videoCodecPreferenceValue(a.videoCodec);
				const valueB = videoCodecPreferenceValue(b.videoCodec);
				if (valueA !== valueB) return valueB - valueA;
			}
			if (a.uri === b.uri && a.codecSet !== b.codecSet) {
				const valueA = codecsSetSelectionPreferenceValue(a.codecSet);
				const valueB = codecsSetSelectionPreferenceValue(b.codecSet);
				if (valueA !== valueB) return valueB - valueA;
			}
			if (a.averageBitrate !== b.averageBitrate) return a.averageBitrate - b.averageBitrate;
			return 0;
		});
		let firstLevelInPlaylist = unsortedLevels[0];
		if (this.steering) {
			levels = this.steering.filterParsedLevels(levels);
			if (levels.length !== unsortedLevels.length) {
				for (let i = 0; i < unsortedLevels.length; i++) if (unsortedLevels[i].pathwayId === levels[0].pathwayId) {
					firstLevelInPlaylist = unsortedLevels[i];
					break;
				}
			}
		}
		this._levels = levels;
		for (let i = 0; i < levels.length; i++) if (levels[i] === firstLevelInPlaylist) {
			var _this$hls$userConfig;
			this._firstLevel = i;
			const firstLevelBitrate = firstLevelInPlaylist.bitrate;
			const bandwidthEstimate = this.hls.bandwidthEstimate;
			this.log(`manifest loaded, ${levels.length} level(s) found, first bitrate: ${firstLevelBitrate}`);
			if (((_this$hls$userConfig = this.hls.userConfig) == null ? void 0 : _this$hls$userConfig.abrEwmaDefaultEstimate) === void 0) {
				const startingBwEstimate = Math.min(firstLevelBitrate, this.hls.config.abrEwmaDefaultEstimateMax);
				if (startingBwEstimate > bandwidthEstimate && bandwidthEstimate === this.hls.abrEwmaDefaultEstimate) this.hls.bandwidthEstimate = startingBwEstimate;
			}
			break;
		}
		const audioOnly = audioCodecFound && !videoCodecFound;
		const config = this.hls.config;
		const altAudioEnabled = !!(config.audioStreamController && config.audioTrackController);
		const edata = {
			levels,
			audioTracks,
			subtitleTracks,
			sessionData: data.sessionData,
			sessionKeys: data.sessionKeys,
			firstLevel: this._firstLevel,
			stats: data.stats,
			audio: audioCodecFound,
			video: videoCodecFound,
			altAudio: altAudioEnabled && !audioOnly && audioTracks.some((t) => !!t.url)
		};
		statsParsing.end = performance.now();
		this.hls.trigger(Events.MANIFEST_PARSED, edata);
	}
	get levels() {
		if (this._levels.length === 0) return null;
		return this._levels;
	}
	get loadLevelObj() {
		return this.currentLevel;
	}
	get level() {
		return this.currentLevelIndex;
	}
	set level(newLevel) {
		const levels = this._levels;
		if (levels.length === 0) return;
		if (newLevel < 0 || newLevel >= levels.length) {
			const error = /* @__PURE__ */ new Error("invalid level idx");
			const fatal = newLevel < 0;
			this.hls.trigger(Events.ERROR, {
				type: ErrorTypes.OTHER_ERROR,
				details: ErrorDetails.LEVEL_SWITCH_ERROR,
				level: newLevel,
				fatal,
				error,
				reason: error.message
			});
			if (fatal) return;
			newLevel = Math.min(newLevel, levels.length - 1);
		}
		const lastLevelIndex = this.currentLevelIndex;
		const lastLevel = this.currentLevel;
		const lastPathwayId = lastLevel ? lastLevel.attrs["PATHWAY-ID"] : void 0;
		const level = levels[newLevel];
		const pathwayId = level.attrs["PATHWAY-ID"];
		this.currentLevelIndex = newLevel;
		this.currentLevel = level;
		if (lastLevelIndex === newLevel && lastLevel && lastPathwayId === pathwayId) return;
		this.log(`Switching to level ${newLevel} (${level.height ? level.height + "p " : ""}${level.videoRange ? level.videoRange + " " : ""}${level.codecSet ? level.codecSet + " " : ""}@${level.bitrate})${pathwayId ? " with Pathway " + pathwayId : ""} from level ${lastLevelIndex}${lastPathwayId ? " with Pathway " + lastPathwayId : ""}`);
		const levelSwitchingData = {
			level: newLevel,
			attrs: level.attrs,
			details: level.details,
			bitrate: level.bitrate,
			averageBitrate: level.averageBitrate,
			maxBitrate: level.maxBitrate,
			realBitrate: level.realBitrate,
			width: level.width,
			height: level.height,
			codecSet: level.codecSet,
			audioCodec: level.audioCodec,
			videoCodec: level.videoCodec,
			audioGroups: level.audioGroups,
			subtitleGroups: level.subtitleGroups,
			loaded: level.loaded,
			loadError: level.loadError,
			fragmentError: level.fragmentError,
			name: level.name,
			id: level.id,
			uri: level.uri,
			url: level.url,
			urlId: 0,
			audioGroupIds: level.audioGroupIds,
			textGroupIds: level.textGroupIds
		};
		this.hls.trigger(Events.LEVEL_SWITCHING, levelSwitchingData);
		const levelDetails = level.details;
		if (!levelDetails || levelDetails.live) {
			const hlsUrlParameters = this.switchParams(level.uri, lastLevel == null ? void 0 : lastLevel.details, levelDetails);
			this.loadPlaylist(hlsUrlParameters);
		}
	}
	get manualLevel() {
		return this.manualLevelIndex;
	}
	set manualLevel(newLevel) {
		this.manualLevelIndex = newLevel;
		if (this._startLevel === void 0) this._startLevel = newLevel;
		if (newLevel !== -1) this.level = newLevel;
	}
	get firstLevel() {
		return this._firstLevel;
	}
	set firstLevel(newLevel) {
		this._firstLevel = newLevel;
	}
	get startLevel() {
		if (this._startLevel === void 0) {
			const configStartLevel = this.hls.config.startLevel;
			if (configStartLevel !== void 0) return configStartLevel;
			return this.hls.firstAutoLevel;
		}
		return this._startLevel;
	}
	set startLevel(newLevel) {
		this._startLevel = newLevel;
	}
	get pathways() {
		if (this.steering) return this.steering.pathways();
		return [];
	}
	get pathwayPriority() {
		if (this.steering) return this.steering.pathwayPriority;
		return null;
	}
	set pathwayPriority(pathwayPriority) {
		if (this.steering) {
			const pathwaysList = this.steering.pathways();
			const filteredPathwayPriority = pathwayPriority.filter((pathwayId) => {
				return pathwaysList.indexOf(pathwayId) !== -1;
			});
			if (pathwayPriority.length < 1) {
				this.warn(`pathwayPriority ${pathwayPriority} should contain at least one pathway from list: ${pathwaysList}`);
				return;
			}
			this.steering.pathwayPriority = filteredPathwayPriority;
		}
	}
	onError(event, data) {
		if (data.fatal || !data.context) return;
		if (data.context.type === PlaylistContextType.LEVEL && data.context.level === this.level) this.checkRetry(data);
	}
	onFragBuffered(event, { frag }) {
		if (frag !== void 0 && frag.type === PlaylistLevelType.MAIN) {
			const el = frag.elementaryStreams;
			if (!Object.keys(el).some((type) => !!el[type])) return;
			const level = this._levels[frag.level];
			if (level != null && level.loadError) {
				this.log(`Resetting level error count of ${level.loadError} on frag buffered`);
				level.loadError = 0;
			}
		}
	}
	onLevelLoaded(event, data) {
		var _data$deliveryDirecti2;
		const { level, details } = data;
		const curLevel = data.levelInfo;
		if (!curLevel) {
			var _data$deliveryDirecti;
			this.warn(`Invalid level index ${level}`);
			if ((_data$deliveryDirecti = data.deliveryDirectives) != null && _data$deliveryDirecti.skip) details.deltaUpdateFailed = true;
			return;
		}
		if (curLevel === this.currentLevel || data.withoutMultiVariant) {
			if (curLevel.fragmentError === 0) curLevel.loadError = 0;
			let previousDetails = curLevel.details;
			if (previousDetails === data.details && previousDetails.advanced) previousDetails = void 0;
			this.playlistLoaded(level, data, previousDetails);
		} else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) details.deltaUpdateFailed = true;
	}
	loadPlaylist(hlsUrlParameters) {
		super.loadPlaylist();
		if (this.shouldLoadPlaylist(this.currentLevel)) this.scheduleLoading(this.currentLevel, hlsUrlParameters);
	}
	loadingPlaylist(currentLevel, hlsUrlParameters) {
		super.loadingPlaylist(currentLevel, hlsUrlParameters);
		const url = this.getUrlWithDirectives(currentLevel.uri, hlsUrlParameters);
		const currentLevelIndex = this.currentLevelIndex;
		const pathwayId = currentLevel.attrs["PATHWAY-ID"];
		const details = currentLevel.details;
		const age = details == null ? void 0 : details.age;
		this.log(`Loading level index ${currentLevelIndex}${(hlsUrlParameters == null ? void 0 : hlsUrlParameters.msn) !== void 0 ? " at sn " + hlsUrlParameters.msn + " part " + hlsUrlParameters.part : ""}${pathwayId ? " Pathway " + pathwayId : ""}${age && details.live ? " age " + age.toFixed(1) + (details.type ? " " + details.type || "" : "") : ""} ${url}`);
		this.hls.trigger(Events.LEVEL_LOADING, {
			url,
			level: currentLevelIndex,
			levelInfo: currentLevel,
			pathwayId: currentLevel.attrs["PATHWAY-ID"],
			id: 0,
			deliveryDirectives: hlsUrlParameters || null
		});
	}
	get nextLoadLevel() {
		if (this.manualLevelIndex !== -1) return this.manualLevelIndex;
		else return this.hls.nextAutoLevel;
	}
	set nextLoadLevel(nextLevel) {
		this.level = nextLevel;
		if (this.manualLevelIndex === -1) this.hls.nextAutoLevel = nextLevel;
	}
	removeLevel(levelIndex) {
		var _this$currentLevel;
		if (this._levels.length === 1) return;
		const levels = this._levels.filter((level, index) => {
			if (index !== levelIndex) return true;
			if (this.steering) this.steering.removeLevel(level);
			if (level === this.currentLevel) {
				this.currentLevel = null;
				this.currentLevelIndex = -1;
				if (level.details) level.details.fragments.forEach((f) => f.level = -1);
			}
			return false;
		});
		reassignFragmentLevelIndexes(levels);
		this._levels = levels;
		if (this.currentLevelIndex > -1 && (_this$currentLevel = this.currentLevel) != null && _this$currentLevel.details) this.currentLevelIndex = this.currentLevel.details.fragments[0].level;
		if (this.manualLevelIndex > -1) this.manualLevelIndex = this.currentLevelIndex;
		const maxLevel = levels.length - 1;
		this._firstLevel = Math.min(this._firstLevel, maxLevel);
		if (this._startLevel) this._startLevel = Math.min(this._startLevel, maxLevel);
		this.hls.trigger(Events.LEVELS_UPDATED, { levels });
	}
	onLevelsUpdated(event, { levels }) {
		this._levels = levels;
	}
	checkMaxAutoUpdated() {
		const { autoLevelCapping, maxAutoLevel, maxHdcpLevel } = this.hls;
		if (this._maxAutoLevel !== maxAutoLevel) {
			this._maxAutoLevel = maxAutoLevel;
			this.hls.trigger(Events.MAX_AUTO_LEVEL_UPDATED, {
				autoLevelCapping,
				levels: this.levels,
				maxAutoLevel,
				minAutoLevel: this.hls.minAutoLevel,
				maxHdcpLevel
			});
		}
	}
};
function assignTrackIdsByGroup(tracks) {
	const groups = {};
	tracks.forEach((track) => {
		const groupId = track.groupId || "";
		track.id = groups[groupId] = groups[groupId] || 0;
		groups[groupId]++;
	});
}
function getSourceBuffer() {
	return self.SourceBuffer || self.WebKitSourceBuffer;
}
function isMSESupported() {
	if (!getMediaSource()) return false;
	const sourceBuffer = getSourceBuffer();
	return !sourceBuffer || sourceBuffer.prototype && typeof sourceBuffer.prototype.appendBuffer === "function" && typeof sourceBuffer.prototype.remove === "function";
}
function isSupported() {
	if (!isMSESupported()) return false;
	const mediaSource = getMediaSource();
	return typeof (mediaSource == null ? void 0 : mediaSource.isTypeSupported) === "function" && ([
		"avc1.42E01E,mp4a.40.2",
		"av01.0.01M.08",
		"vp09.00.50.08"
	].some((codecsForVideoContainer) => mediaSource.isTypeSupported(mimeTypeForCodec(codecsForVideoContainer, "video"))) || ["mp4a.40.2", "fLaC"].some((codecForAudioContainer) => mediaSource.isTypeSupported(mimeTypeForCodec(codecForAudioContainer, "audio"))));
}
function changeTypeSupported() {
	var _sourceBuffer$prototy;
	const sourceBuffer = getSourceBuffer();
	return typeof (sourceBuffer == null || (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === "function";
}
var TICK_INTERVAL = 100;
var StreamController = class extends BaseStreamController {
	constructor(hls, fragmentTracker, keyLoader) {
		super(hls, fragmentTracker, keyLoader, "stream-controller", PlaylistLevelType.MAIN);
		this.audioCodecSwap = false;
		this.level = -1;
		this._forceStartLoad = false;
		this._hasEnoughToStart = false;
		this.altAudio = 0;
		this.audioOnly = false;
		this.fragPlaying = null;
		this.fragLastKbps = 0;
		this.couldBacktrack = false;
		this.backtrackFragment = null;
		this.audioCodecSwitch = false;
		this.videoBuffer = null;
		this.onMediaPlaying = () => {
			this.tick();
		};
		this.onMediaSeeked = () => {
			const media = this.media;
			const currentTime = media ? media.currentTime : null;
			if (currentTime === null || !isFiniteNumber(currentTime)) return;
			this.log(`Media seeked to ${currentTime.toFixed(3)}`);
			if (!this.getBufferedFrag(currentTime)) return;
			const bufferInfo = this.getFwdBufferInfoAtPos(media, currentTime, PlaylistLevelType.MAIN, 0);
			if (bufferInfo === null || bufferInfo.len === 0) {
				this.warn(`Main forward buffer length at ${currentTime} on "seeked" event ${bufferInfo ? bufferInfo.len : "empty"})`);
				return;
			}
			this.tick();
		};
		this.registerListeners();
	}
	registerListeners() {
		super.registerListeners();
		const { hls } = this;
		hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
		hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
		hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
		hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
		hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
		hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
		hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
		hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
		hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
	}
	unregisterListeners() {
		super.unregisterListeners();
		const { hls } = this;
		hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
		hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
		hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
		hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
		hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
		hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
		hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
		hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
		hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
	}
	onHandlerDestroying() {
		this.onMediaPlaying = this.onMediaSeeked = null;
		this.unregisterListeners();
		super.onHandlerDestroying();
	}
	startLoad(startPosition, skipSeekToStartPosition) {
		if (this.levels) {
			const { lastCurrentTime, hls } = this;
			this.stopLoad();
			this.setInterval(TICK_INTERVAL);
			this.level = -1;
			if (!this.startFragRequested) {
				let startLevel = hls.startLevel;
				if (startLevel === -1) if (hls.config.testBandwidth && this.levels.length > 1) {
					startLevel = 0;
					this.bitrateTest = true;
				} else startLevel = hls.firstAutoLevel;
				hls.nextLoadLevel = startLevel;
				this.level = hls.loadLevel;
				this._hasEnoughToStart = !!skipSeekToStartPosition;
			}
			if (lastCurrentTime > 0 && startPosition === -1 && !skipSeekToStartPosition) {
				this.log(`Override startPosition with lastCurrentTime @${lastCurrentTime.toFixed(3)}`);
				startPosition = lastCurrentTime;
			}
			this.state = State.IDLE;
			this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset;
			this.startPosition = skipSeekToStartPosition ? -1 : startPosition;
			this.tick();
		} else {
			this._forceStartLoad = true;
			this.state = State.STOPPED;
		}
	}
	stopLoad() {
		this._forceStartLoad = false;
		super.stopLoad();
	}
	doTick() {
		switch (this.state) {
			case State.WAITING_LEVEL: {
				const { levels, level } = this;
				const currentLevel = levels == null ? void 0 : levels[level];
				const details = currentLevel == null ? void 0 : currentLevel.details;
				if (details && (!details.live || this.levelLastLoaded === currentLevel && !this.waitForLive(currentLevel))) {
					if (this.waitForCdnTuneIn(details)) break;
					this.state = State.IDLE;
					break;
				} else if (this.hls.nextLoadLevel !== this.level) {
					this.state = State.IDLE;
					break;
				}
				break;
			}
			case State.FRAG_LOADING_WAITING_RETRY:
				this.checkRetryDate();
				break;
		}
		if (this.state === State.IDLE) this.doTickIdle();
		this.onTickEnd();
	}
	onTickEnd() {
		var _this$media;
		super.onTickEnd();
		if ((_this$media = this.media) != null && _this$media.readyState && this.media.seeking === false) this.lastCurrentTime = this.media.currentTime;
		this.checkFragmentChanged();
	}
	doTickIdle() {
		const { hls, levelLastLoaded, levels, media } = this;
		if (levelLastLoaded === null || !media && !this.primaryPrefetch && (this.startFragRequested || !hls.config.startFragPrefetch)) return;
		if (this.altAudio && this.audioOnly) return;
		const level = this.buffering ? hls.nextLoadLevel : hls.loadLevel;
		if (!(levels != null && levels[level])) return;
		const levelInfo = levels[level];
		const bufferInfo = this.getMainFwdBufferInfo();
		if (bufferInfo === null) return;
		const lastDetails = this.getLevelDetails();
		if (lastDetails && this._streamEnded(bufferInfo, lastDetails)) {
			const data = {};
			if (this.altAudio === 2) data.type = "video";
			this.hls.trigger(Events.BUFFER_EOS, data);
			this.state = State.ENDED;
			return;
		}
		if (!this.buffering) return;
		if (hls.loadLevel !== level && hls.manualLevel === -1) this.log(`Adapting to level ${level} from level ${this.level}`);
		this.level = hls.nextLoadLevel = level;
		const levelDetails = levelInfo.details;
		if (!levelDetails || this.state === State.WAITING_LEVEL || this.waitForLive(levelInfo)) {
			this.level = level;
			this.state = State.WAITING_LEVEL;
			this.startFragRequested = false;
			return;
		}
		const bufferLen = bufferInfo.len;
		const maxBufLen = this.getMaxBufferLength(levelInfo.maxBitrate);
		if (bufferLen >= maxBufLen) return;
		if (this.backtrackFragment && this.backtrackFragment.start > bufferInfo.end) this.backtrackFragment = null;
		const targetBufferTime = this.backtrackFragment ? this.backtrackFragment.start : bufferInfo.end;
		let frag = this.getNextFragment(targetBufferTime, levelDetails);
		if (this.couldBacktrack && !this.fragPrevious && frag && isMediaFragment(frag) && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
			var _this$backtrackFragme;
			const fragIdx = ((_this$backtrackFragme = this.backtrackFragment) != null ? _this$backtrackFragme : frag).sn - levelDetails.startSN;
			const backtrackFrag = levelDetails.fragments[fragIdx - 1];
			if (backtrackFrag && frag.cc === backtrackFrag.cc) {
				frag = backtrackFrag;
				this.fragmentTracker.removeFragment(backtrackFrag);
			}
		} else if (this.backtrackFragment && bufferInfo.len) this.backtrackFragment = null;
		if (frag && this.isLoopLoading(frag, targetBufferTime)) {
			if (!frag.gap) {
				const type = this.audioOnly && !this.altAudio ? ElementaryStreamTypes.AUDIO : ElementaryStreamTypes.VIDEO;
				const mediaBuffer = (type === ElementaryStreamTypes.VIDEO ? this.videoBuffer : this.mediaBuffer) || this.media;
				if (mediaBuffer) this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.MAIN);
			}
			frag = this.getNextFragmentLoopLoading(frag, levelDetails, bufferInfo, PlaylistLevelType.MAIN, maxBufLen);
		}
		if (!frag) return;
		if (this.exceedsMaxBuffer(bufferInfo, maxBufLen, frag)) return;
		if (frag.initSegment && !frag.initSegment.data && !this.bitrateTest) frag = frag.initSegment;
		this.loadFragment(frag, levelInfo, targetBufferTime);
	}
	loadFragment(frag, level, targetBufferTime) {
		const fragState = this.fragmentTracker.getState(frag);
		if (fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) if (!isMediaFragment(frag)) this._loadInitSegment(frag, level);
		else if (this.bitrateTest) {
			this.log(`Fragment ${frag.sn} of level ${frag.level} is being downloaded to test bitrate and will not be buffered`);
			this._loadBitrateTestFrag(frag, level);
		} else super.loadFragment(frag, level, targetBufferTime);
		else this.clearTrackerIfNeeded(frag);
	}
	getBufferedFrag(position) {
		return this.fragmentTracker.getBufferedFrag(position, PlaylistLevelType.MAIN);
	}
	followingBufferedFrag(frag) {
		if (frag) return this.getBufferedFrag(frag.end + .5);
		return null;
	}
	immediateLevelSwitch() {
		this.abortCurrentFrag();
		this.flushMainBuffer(0, Number.POSITIVE_INFINITY);
		if (this.altAudio !== 0) {
			var _this$getLevelDetails;
			if ((((_this$getLevelDetails = this.getLevelDetails()) == null ? void 0 : _this$getLevelDetails.fragmentStart) || 0) > this.lastCurrentTime) super.flushMainBuffer(0, Number.POSITIVE_INFINITY, "audio");
		}
	}
	/**
	* try to switch ASAP without breaking video playback:
	* in order to ensure smooth but quick level switching,
	* we need to find the next flushable buffer range
	* we should take into account new segment fetch time
	*/
	nextLevelSwitch() {
		const { levels, media } = this;
		if (media != null && media.readyState) {
			let fetchdelay;
			const fragPlayingCurrent = this.getAppendedFrag(media.currentTime);
			if (fragPlayingCurrent && fragPlayingCurrent.start > 1) this.flushMainBuffer(0, fragPlayingCurrent.start - 1);
			const levelDetails = this.getLevelDetails();
			if (levelDetails != null && levelDetails.live) {
				const bufferInfo = this.getMainFwdBufferInfo();
				if (!bufferInfo || bufferInfo.len < levelDetails.targetduration * 2) return;
			}
			if (!media.paused && levels) {
				const nextLevel = levels[this.hls.nextLoadLevel];
				const fragLastKbps = this.fragLastKbps;
				if (fragLastKbps && this.fragCurrent) fetchdelay = this.fragCurrent.duration * nextLevel.maxBitrate / (1e3 * fragLastKbps) + 1;
				else fetchdelay = 0;
			} else fetchdelay = 0;
			const bufferedFrag = this.getBufferedFrag(media.currentTime + fetchdelay);
			if (bufferedFrag) {
				const nextBufferedFrag = this.followingBufferedFrag(bufferedFrag);
				if (nextBufferedFrag) {
					this.abortCurrentFrag();
					const maxStart = nextBufferedFrag.maxStartPTS ? nextBufferedFrag.maxStartPTS : nextBufferedFrag.start;
					const fragDuration = nextBufferedFrag.duration;
					const startPts = Math.max(bufferedFrag.end, maxStart + Math.min(Math.max(fragDuration - this.config.maxFragLookUpTolerance, fragDuration * (this.couldBacktrack ? .5 : .125)), fragDuration * (this.couldBacktrack ? .75 : .25)));
					this.flushMainBuffer(startPts, Number.POSITIVE_INFINITY);
				}
			}
		}
	}
	abortCurrentFrag() {
		const fragCurrent = this.fragCurrent;
		this.fragCurrent = null;
		this.backtrackFragment = null;
		if (fragCurrent) {
			fragCurrent.abortRequests();
			this.fragmentTracker.removeFragment(fragCurrent);
		}
		switch (this.state) {
			case State.KEY_LOADING:
			case State.FRAG_LOADING:
			case State.FRAG_LOADING_WAITING_RETRY:
			case State.PARSING:
			case State.PARSED:
				this.state = State.IDLE;
				break;
		}
		this.nextLoadPosition = this.getLoadPosition();
	}
	flushMainBuffer(startOffset, endOffset) {
		super.flushMainBuffer(startOffset, endOffset, this.altAudio === 2 ? "video" : null);
	}
	onMediaAttached(event, data) {
		super.onMediaAttached(event, data);
		const media = data.media;
		addEventListener(media, "playing", this.onMediaPlaying);
		addEventListener(media, "seeked", this.onMediaSeeked);
	}
	onMediaDetaching(event, data) {
		const { media } = this;
		if (media) {
			removeEventListener(media, "playing", this.onMediaPlaying);
			removeEventListener(media, "seeked", this.onMediaSeeked);
		}
		this.videoBuffer = null;
		this.fragPlaying = null;
		super.onMediaDetaching(event, data);
		if (!!data.transferMedia) return;
		this._hasEnoughToStart = false;
	}
	onManifestLoading() {
		super.onManifestLoading();
		this.log("Trigger BUFFER_RESET");
		this.hls.trigger(Events.BUFFER_RESET, void 0);
		this.couldBacktrack = false;
		this.fragLastKbps = 0;
		this.fragPlaying = this.backtrackFragment = null;
		this.altAudio = 0;
		this.audioOnly = false;
	}
	onManifestParsed(event, data) {
		let aac = false;
		let heaac = false;
		for (let i = 0; i < data.levels.length; i++) {
			const codec = data.levels[i].audioCodec;
			if (codec) {
				aac = aac || codec.indexOf("mp4a.40.2") !== -1;
				heaac = heaac || codec.indexOf("mp4a.40.5") !== -1;
			}
		}
		this.audioCodecSwitch = aac && heaac && !changeTypeSupported();
		if (this.audioCodecSwitch) this.log("Both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC");
		this.levels = data.levels;
		this.startFragRequested = false;
	}
	onLevelLoading(event, data) {
		const { levels } = this;
		if (!levels || this.state !== State.IDLE) return;
		const level = data.levelInfo;
		if (!level.details || level.details.live && (this.levelLastLoaded !== level || level.details.expired) || this.waitForCdnTuneIn(level.details)) this.state = State.WAITING_LEVEL;
	}
	onLevelLoaded(event, data) {
		var _curLevel$details;
		const { levels, startFragRequested } = this;
		const newLevelId = data.level;
		const newDetails = data.details;
		const duration = newDetails.totalduration;
		if (!levels) {
			this.warn(`Levels were reset while loading level ${newLevelId}`);
			return;
		}
		this.log(`Level ${newLevelId} loaded [${newDetails.startSN},${newDetails.endSN}]${newDetails.lastPartSn ? `[part-${newDetails.lastPartSn}-${newDetails.lastPartIndex}]` : ""}, cc [${newDetails.startCC}, ${newDetails.endCC}] duration:${duration}`);
		const curLevel = data.levelInfo;
		const fragCurrent = this.fragCurrent;
		if (fragCurrent && (this.state === State.FRAG_LOADING || this.state === State.FRAG_LOADING_WAITING_RETRY)) {
			if (fragCurrent.level !== data.level && fragCurrent.loader) this.abortCurrentFrag();
		}
		let sliding = 0;
		if (newDetails.live || (_curLevel$details = curLevel.details) != null && _curLevel$details.live) {
			var _this$levelLastLoaded;
			this.checkLiveUpdate(newDetails);
			if (newDetails.deltaUpdateFailed) return;
			sliding = this.alignPlaylists(newDetails, curLevel.details, (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details);
		}
		curLevel.details = newDetails;
		this.levelLastLoaded = curLevel;
		if (!startFragRequested) this.setStartPosition(newDetails, sliding);
		this.hls.trigger(Events.LEVEL_UPDATED, {
			details: newDetails,
			level: newLevelId
		});
		if (this.state === State.WAITING_LEVEL) {
			if (this.waitForCdnTuneIn(newDetails)) return;
			this.state = State.IDLE;
		}
		if (startFragRequested && newDetails.live) this.synchronizeToLiveEdge(newDetails);
		this.tick();
	}
	synchronizeToLiveEdge(levelDetails) {
		const { config, media } = this;
		if (!media) return;
		const liveSyncPosition = this.hls.liveSyncPosition;
		const currentTime = this.getLoadPosition();
		const start = levelDetails.fragmentStart;
		const end = levelDetails.edge;
		const withinSlidingWindow = currentTime >= start - config.maxFragLookUpTolerance && currentTime <= end;
		if (liveSyncPosition !== null && media.duration > liveSyncPosition && (currentTime < liveSyncPosition || !withinSlidingWindow)) {
			const maxLatency = config.liveMaxLatencyDuration !== void 0 ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount * levelDetails.targetduration;
			if (!withinSlidingWindow && media.readyState < 4 || currentTime < end - maxLatency) {
				if (!this._hasEnoughToStart) this.nextLoadPosition = liveSyncPosition;
				if (media.readyState) {
					this.warn(`Playback: ${currentTime.toFixed(3)} is located too far from the end of live sliding playlist: ${end}, reset currentTime to : ${liveSyncPosition.toFixed(3)}`);
					if (this.config.liveSyncMode === "buffered") {
						var _bufferInfo$buffered;
						const bufferInfo = BufferHelper.bufferInfo(media, liveSyncPosition, 0);
						if (!((_bufferInfo$buffered = bufferInfo.buffered) != null && _bufferInfo$buffered.length)) {
							media.currentTime = liveSyncPosition;
							return;
						}
						if (bufferInfo.start <= currentTime) {
							media.currentTime = liveSyncPosition;
							return;
						}
						const { nextStart } = BufferHelper.bufferedInfo(bufferInfo.buffered, currentTime, 0);
						if (nextStart) media.currentTime = nextStart;
					} else media.currentTime = liveSyncPosition;
				}
			}
		}
	}
	_handleFragmentLoadProgress(data) {
		var _frag$initSegment;
		const frag = data.frag;
		const { part, payload } = data;
		const { levels } = this;
		if (!levels) {
			this.warn(`Levels were reset while fragment load was in progress. Fragment ${frag.sn} of level ${frag.level} will not be buffered`);
			return;
		}
		const currentLevel = levels[frag.level];
		if (!currentLevel) {
			this.warn(`Level ${frag.level} not found on progress`);
			return;
		}
		const details = currentLevel.details;
		if (!details) {
			this.warn(`Dropping fragment ${frag.sn} of level ${frag.level} after level details were reset`);
			this.fragmentTracker.removeFragment(frag);
			return;
		}
		const videoCodec = currentLevel.videoCodec;
		const accurateTimeOffset = details.PTSKnown || !details.live;
		const initSegmentData = (_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.data;
		const audioCodec = this._getAudioCodec(currentLevel);
		const transmuxer = this.transmuxer = this.transmuxer || new TransmuxerInterface(this.hls, PlaylistLevelType.MAIN, this._handleTransmuxComplete.bind(this), this._handleTransmuxerFlush.bind(this));
		const partIndex = part ? part.index : -1;
		const partial = partIndex !== -1;
		const chunkMeta = new ChunkMetadata(frag.level, frag.sn, frag.stats.chunkCount, payload.byteLength, partIndex, partial);
		const initPTS = this.initPTS[frag.cc];
		transmuxer.push(payload, initSegmentData, audioCodec, videoCodec, frag, part, details.totalduration, accurateTimeOffset, chunkMeta, initPTS);
	}
	onAudioTrackSwitching(event, data) {
		const hls = this.hls;
		const fromAltAudio = this.altAudio !== 0;
		if (!useAlternateAudio(data.url, hls)) {
			if (this.mediaBuffer !== this.media) {
				this.log("Switching on main audio, use media.buffered to schedule main fragment loading");
				this.mediaBuffer = this.media;
				const fragCurrent = this.fragCurrent;
				if (fragCurrent) {
					this.log("Switching to main audio track, cancel main fragment load");
					fragCurrent.abortRequests();
					this.fragmentTracker.removeFragment(fragCurrent);
				}
				this.resetTransmuxer();
				this.resetLoadingState();
			} else if (this.audioOnly) this.resetTransmuxer();
			if (fromAltAudio) {
				this.altAudio = 0;
				this.fragmentTracker.removeAllFragments();
				hls.once(Events.BUFFER_FLUSHED, () => {
					if (!this.hls) return;
					this.hls.trigger(Events.AUDIO_TRACK_SWITCHED, data);
				});
				hls.trigger(Events.BUFFER_FLUSHING, {
					startOffset: 0,
					endOffset: Number.POSITIVE_INFINITY,
					type: null
				});
				return;
			}
			hls.trigger(Events.AUDIO_TRACK_SWITCHED, data);
		} else this.altAudio = 1;
	}
	onAudioTrackSwitched(event, data) {
		const altAudio = useAlternateAudio(data.url, this.hls);
		if (altAudio) {
			const videoBuffer = this.videoBuffer;
			if (videoBuffer && this.mediaBuffer !== videoBuffer) {
				this.log("Switching on alternate audio, use video.buffered to schedule main fragment loading");
				this.mediaBuffer = videoBuffer;
			}
		}
		this.altAudio = altAudio ? 2 : 0;
		this.tick();
	}
	onBufferCreated(event, data) {
		const tracks = data.tracks;
		let mediaTrack;
		let name;
		let alternate = false;
		for (const type in tracks) {
			const track = tracks[type];
			if (track.id === "main") {
				name = type;
				mediaTrack = track;
				if (type === "video") {
					const videoTrack = tracks[type];
					if (videoTrack) this.videoBuffer = videoTrack.buffer;
				}
			} else alternate = true;
		}
		if (alternate && mediaTrack) {
			this.log(`Alternate track found, use ${name}.buffered to schedule main fragment loading`);
			this.mediaBuffer = mediaTrack.buffer;
		} else this.mediaBuffer = this.media;
	}
	onFragBuffered(event, data) {
		const { frag, part } = data;
		const bufferedMainFragment = frag.type === PlaylistLevelType.MAIN;
		if (bufferedMainFragment) {
			if (this.fragContextChanged(frag)) {
				this.warn(`Fragment ${frag.sn}${part ? " p: " + part.index : ""} of level ${frag.level} finished buffering, but was aborted. state: ${this.state}`);
				if (this.state === State.PARSED) this.state = State.IDLE;
				return;
			}
			const stats = part ? part.stats : frag.stats;
			this.fragLastKbps = Math.round(8 * stats.total / (stats.buffering.end - stats.loading.first));
			if (isMediaFragment(frag)) this.fragPrevious = frag;
			this.fragBufferedComplete(frag, part);
		}
		const media = this.media;
		if (!media) return;
		if (!this._hasEnoughToStart && BufferHelper.getBuffered(media).length) {
			this._hasEnoughToStart = true;
			this.seekToStartPos();
		}
		if (bufferedMainFragment) this.tick();
	}
	get hasEnoughToStart() {
		return this._hasEnoughToStart;
	}
	onError(event, data) {
		var _data$context;
		if (data.fatal) {
			this.state = State.ERROR;
			return;
		}
		switch (data.details) {
			case ErrorDetails.FRAG_GAP:
			case ErrorDetails.FRAG_PARSING_ERROR:
			case ErrorDetails.FRAG_DECRYPT_ERROR:
			case ErrorDetails.FRAG_LOAD_ERROR:
			case ErrorDetails.FRAG_LOAD_TIMEOUT:
			case ErrorDetails.KEY_LOAD_ERROR:
			case ErrorDetails.KEY_LOAD_TIMEOUT:
				this.onFragmentOrKeyLoadError(PlaylistLevelType.MAIN, data);
				break;
			case ErrorDetails.LEVEL_LOAD_ERROR:
			case ErrorDetails.LEVEL_LOAD_TIMEOUT:
			case ErrorDetails.LEVEL_PARSING_ERROR:
				if (!data.levelRetry && this.state === State.WAITING_LEVEL && ((_data$context = data.context) == null ? void 0 : _data$context.type) === PlaylistContextType.LEVEL) this.state = State.IDLE;
				break;
			case ErrorDetails.BUFFER_ADD_CODEC_ERROR:
			case ErrorDetails.BUFFER_APPEND_ERROR:
				if (data.parent !== "main") return;
				if (this.reduceLengthAndFlushBuffer(data)) this.resetLoadingState();
				break;
			case ErrorDetails.BUFFER_FULL_ERROR:
				if (data.parent !== "main") return;
				if (this.reduceLengthAndFlushBuffer(data)) if (!this.config.interstitialsController && this.config.assetPlayerId) this._hasEnoughToStart = true;
				else this.flushMainBuffer(0, Number.POSITIVE_INFINITY);
				break;
			case ErrorDetails.INTERNAL_EXCEPTION:
				this.recoverWorkerError(data);
				break;
		}
	}
	onFragLoadEmergencyAborted() {
		this.state = State.IDLE;
		if (!this._hasEnoughToStart) {
			this.startFragRequested = false;
			this.nextLoadPosition = this.lastCurrentTime;
		}
		this.tickImmediate();
	}
	onBufferFlushed(event, { type }) {
		if (type !== ElementaryStreamTypes.AUDIO || !this.altAudio) {
			const mediaBuffer = (type === ElementaryStreamTypes.VIDEO ? this.videoBuffer : this.mediaBuffer) || this.media;
			if (mediaBuffer) {
				this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.MAIN);
				this.tick();
			}
		}
	}
	onLevelsUpdated(event, data) {
		if (this.level > -1 && this.fragCurrent) {
			this.level = this.fragCurrent.level;
			if (this.level === -1) this.resetWhenMissingContext(this.fragCurrent);
		}
		this.levels = data.levels;
	}
	swapAudioCodec() {
		this.audioCodecSwap = !this.audioCodecSwap;
	}
	/**
	* Seeks to the set startPosition if not equal to the mediaElement's current time.
	*/
	seekToStartPos() {
		const { media } = this;
		if (!media) return;
		const currentTime = media.currentTime;
		let startPosition = this.startPosition;
		if (startPosition >= 0 && currentTime < startPosition) {
			if (media.seeking) {
				this.log(`could not seek to ${startPosition}, already seeking at ${currentTime}`);
				return;
			}
			const timelineOffset = this.timelineOffset;
			if (timelineOffset && startPosition) startPosition += timelineOffset;
			const details = this.getLevelDetails();
			const buffered = BufferHelper.getBuffered(media);
			const bufferStart = buffered.length ? buffered.start(0) : 0;
			const delta = bufferStart - startPosition;
			const skipTolerance = Math.max(this.config.maxBufferHole, this.config.maxFragLookUpTolerance);
			if (this.config.startOnSegmentBoundary || delta > 0 && (delta < skipTolerance || this.loadingParts && delta < 2 * ((details == null ? void 0 : details.partTarget) || 0))) {
				this.log(`adjusting start position by ${delta} to match buffer start`);
				startPosition += delta;
				this.startPosition = startPosition;
			}
			if (currentTime < startPosition) {
				this.log(`seek to target start position ${startPosition} from current time ${currentTime} buffer start ${bufferStart}`);
				media.currentTime = startPosition;
			}
		}
	}
	_getAudioCodec(currentLevel) {
		let audioCodec = this.config.defaultAudioCodec || currentLevel.audioCodec;
		if (this.audioCodecSwap && audioCodec) {
			this.log("Swapping audio codec");
			if (audioCodec.indexOf("mp4a.40.5") !== -1) audioCodec = "mp4a.40.2";
			else audioCodec = "mp4a.40.5";
		}
		return audioCodec;
	}
	_loadBitrateTestFrag(fragment, level) {
		fragment.bitrateTest = true;
		this._doFragLoad(fragment, level).then((data) => {
			const { hls } = this;
			const frag = data == null ? void 0 : data.frag;
			if (!frag || this.fragContextChanged(frag)) return;
			level.fragmentError = 0;
			this.state = State.IDLE;
			this.startFragRequested = false;
			this.bitrateTest = false;
			const stats = frag.stats;
			stats.parsing.start = stats.parsing.end = stats.buffering.start = stats.buffering.end = self.performance.now();
			hls.trigger(Events.FRAG_LOADED, data);
			frag.bitrateTest = false;
		}).catch((reason) => {
			if (this.state === State.STOPPED || this.state === State.ERROR) return;
			this.warn(reason);
			this.resetFragmentLoading(fragment);
		});
	}
	_handleTransmuxComplete(transmuxResult) {
		const id = this.playlistType;
		const { hls } = this;
		const { remuxResult, chunkMeta } = transmuxResult;
		const context = this.getCurrentContext(chunkMeta);
		if (!context) {
			this.resetWhenMissingContext(chunkMeta);
			return;
		}
		const { frag, part, level } = context;
		const { video, text, id3, initSegment } = remuxResult;
		const { details } = level;
		const audio = this.altAudio ? void 0 : remuxResult.audio;
		if (this.fragContextChanged(frag)) {
			this.fragmentTracker.removeFragment(frag);
			return;
		}
		this.state = State.PARSING;
		if (initSegment) {
			const tracks = initSegment.tracks;
			if (tracks) {
				const mapFragment = frag.initSegment || frag;
				if (this.unhandledEncryptionError(initSegment, frag)) return;
				this._bufferInitSegment(level, tracks, mapFragment, chunkMeta);
				hls.trigger(Events.FRAG_PARSING_INIT_SEGMENT, {
					frag: mapFragment,
					id,
					tracks
				});
			}
			const baseTime = initSegment.initPTS;
			const timescale = initSegment.timescale;
			const initPTS = this.initPTS[frag.cc];
			if (isFiniteNumber(baseTime) && (!initPTS || initPTS.baseTime !== baseTime || initPTS.timescale !== timescale)) {
				const trackId = initSegment.trackId;
				this.initPTS[frag.cc] = {
					baseTime,
					timescale,
					trackId
				};
				hls.trigger(Events.INIT_PTS_FOUND, {
					frag,
					id,
					initPTS: baseTime,
					timescale,
					trackId
				});
			}
		}
		if (video && details) {
			if (audio && video.type === "audiovideo") this.logMuxedErr(frag);
			const prevFrag = details.fragments[frag.sn - 1 - details.startSN];
			const isFirstFragment = frag.sn === details.startSN;
			const isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
			if (remuxResult.independent !== false) {
				const { startPTS, endPTS, startDTS, endDTS } = video;
				if (part) part.elementaryStreams[video.type] = {
					startPTS,
					endPTS,
					startDTS,
					endDTS
				};
				else {
					if (video.firstKeyFrame && video.independent && chunkMeta.id === 1 && !isFirstInDiscontinuity) this.couldBacktrack = true;
					if (video.dropped && video.independent) {
						const bufferInfo = this.getMainFwdBufferInfo();
						const targetBufferTime = (bufferInfo ? bufferInfo.end : this.getLoadPosition()) + this.config.maxBufferHole;
						const startTime = video.firstKeyFramePTS ? video.firstKeyFramePTS : startPTS;
						if (!isFirstFragment && targetBufferTime < startTime - this.config.maxBufferHole && !isFirstInDiscontinuity) {
							this.backtrack(frag);
							return;
						} else if (isFirstInDiscontinuity) frag.gap = true;
						frag.setElementaryStreamInfo(video.type, frag.start, endPTS, frag.start, endDTS, true);
					} else if (isFirstFragment && startPTS - (details.appliedTimelineOffset || 0) > MAX_START_GAP_JUMP) frag.gap = true;
				}
				frag.setElementaryStreamInfo(video.type, startPTS, endPTS, startDTS, endDTS);
				if (this.backtrackFragment) this.backtrackFragment = frag;
				this.bufferFragmentData(video, frag, part, chunkMeta, isFirstFragment || isFirstInDiscontinuity);
			} else if (isFirstFragment || isFirstInDiscontinuity) frag.gap = true;
			else {
				this.backtrack(frag);
				return;
			}
		}
		if (audio) {
			const { startPTS, endPTS, startDTS, endDTS } = audio;
			if (part) part.elementaryStreams[ElementaryStreamTypes.AUDIO] = {
				startPTS,
				endPTS,
				startDTS,
				endDTS
			};
			frag.setElementaryStreamInfo(ElementaryStreamTypes.AUDIO, startPTS, endPTS, startDTS, endDTS);
			this.bufferFragmentData(audio, frag, part, chunkMeta);
		}
		if (details && id3 != null && id3.samples.length) {
			const emittedID3 = {
				id,
				frag,
				details,
				samples: id3.samples
			};
			hls.trigger(Events.FRAG_PARSING_METADATA, emittedID3);
		}
		if (details && text) {
			const emittedText = {
				id,
				frag,
				details,
				samples: text.samples
			};
			hls.trigger(Events.FRAG_PARSING_USERDATA, emittedText);
		}
	}
	logMuxedErr(frag) {
		this.warn(`${isMediaFragment(frag) ? "Media" : "Init"} segment with muxed audiovideo where only video expected: ${frag.url}`);
	}
	_bufferInitSegment(currentLevel, tracks, frag, chunkMeta) {
		if (this.state !== State.PARSING) return;
		this.audioOnly = !!tracks.audio && !tracks.video;
		if (this.altAudio && !this.audioOnly) {
			delete tracks.audio;
			if (tracks.audiovideo) this.logMuxedErr(frag);
		}
		const { audio, video, audiovideo } = tracks;
		if (audio) {
			const levelCodec = currentLevel.audioCodec;
			let audioCodec = pickMostCompleteCodecName(audio.codec, levelCodec);
			if (audioCodec === "mp4a") audioCodec = "mp4a.40.5";
			const ua = navigator.userAgent.toLowerCase();
			if (this.audioCodecSwitch) {
				if (audioCodec) if (audioCodec.indexOf("mp4a.40.5") !== -1) audioCodec = "mp4a.40.2";
				else audioCodec = "mp4a.40.5";
				const audioMetadata = audio.metadata;
				if (audioMetadata && "channelCount" in audioMetadata && (audioMetadata.channelCount || 1) !== 1 && ua.indexOf("firefox") === -1) audioCodec = "mp4a.40.5";
			}
			if (audioCodec && audioCodec.indexOf("mp4a.40.5") !== -1 && ua.indexOf("android") !== -1 && audio.container !== "audio/mpeg") {
				audioCodec = "mp4a.40.2";
				this.log(`Android: force audio codec to ${audioCodec}`);
			}
			if (levelCodec && levelCodec !== audioCodec) this.log(`Swapping manifest audio codec "${levelCodec}" for "${audioCodec}"`);
			audio.levelCodec = audioCodec;
			audio.id = PlaylistLevelType.MAIN;
			this.log(`Init audio buffer, container:${audio.container}, codecs[selected/level/parsed]=[${audioCodec || ""}/${levelCodec || ""}/${audio.codec}]`);
			delete tracks.audiovideo;
		}
		if (video) {
			video.levelCodec = currentLevel.videoCodec;
			video.id = PlaylistLevelType.MAIN;
			const parsedVideoCodec = video.codec;
			if ((parsedVideoCodec == null ? void 0 : parsedVideoCodec.length) === 4) switch (parsedVideoCodec) {
				case "hvc1":
				case "hev1":
					video.codec = "hvc1.1.6.L120.90";
					break;
				case "av01":
					video.codec = "av01.0.04M.08";
					break;
				case "avc1":
					video.codec = "avc1.42e01e";
					break;
			}
			this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ""}/${parsedVideoCodec}]${video.codec !== parsedVideoCodec ? " parsed-corrected=" + video.codec : ""}${video.supplemental ? " supplemental=" + video.supplemental : ""}`);
			delete tracks.audiovideo;
		}
		if (audiovideo) {
			this.log(`Init audiovideo buffer, container:${audiovideo.container}, codecs[level/parsed]=[${currentLevel.codecs}/${audiovideo.codec}]`);
			delete tracks.video;
			delete tracks.audio;
		}
		const trackTypes = Object.keys(tracks);
		if (trackTypes.length) {
			this.hls.trigger(Events.BUFFER_CODECS, tracks);
			if (!this.hls) return;
			trackTypes.forEach((trackName) => {
				const initSegment = tracks[trackName].initSegment;
				if (initSegment != null && initSegment.byteLength) this.hls.trigger(Events.BUFFER_APPENDING, {
					type: trackName,
					data: initSegment,
					frag,
					part: null,
					chunkMeta,
					parent: frag.type
				});
			});
		}
		this.tickImmediate();
	}
	getMainFwdBufferInfo() {
		const bufferOutput = this.mediaBuffer && this.altAudio === 2 ? this.mediaBuffer : this.media;
		return this.getFwdBufferInfo(bufferOutput, PlaylistLevelType.MAIN);
	}
	get maxBufferLength() {
		const { levels, level } = this;
		const levelInfo = levels == null ? void 0 : levels[level];
		if (!levelInfo) return this.config.maxBufferLength;
		return this.getMaxBufferLength(levelInfo.maxBitrate);
	}
	backtrack(frag) {
		this.couldBacktrack = true;
		this.backtrackFragment = frag;
		this.resetTransmuxer();
		this.flushBufferGap(frag);
		this.fragmentTracker.removeFragment(frag);
		this.fragPrevious = null;
		this.nextLoadPosition = frag.start;
		this.state = State.IDLE;
	}
	checkFragmentChanged() {
		const video = this.media;
		let fragPlayingCurrent = null;
		if (video && video.readyState > 1 && video.seeking === false) {
			const currentTime = video.currentTime;
			if (BufferHelper.isBuffered(video, currentTime)) fragPlayingCurrent = this.getAppendedFrag(currentTime);
			else if (BufferHelper.isBuffered(video, currentTime + .1)) fragPlayingCurrent = this.getAppendedFrag(currentTime + .1);
			if (fragPlayingCurrent) {
				this.backtrackFragment = null;
				const fragPlaying = this.fragPlaying;
				const fragCurrentLevel = fragPlayingCurrent.level;
				if (!fragPlaying || fragPlayingCurrent.sn !== fragPlaying.sn || fragPlaying.level !== fragCurrentLevel) {
					this.fragPlaying = fragPlayingCurrent;
					this.hls.trigger(Events.FRAG_CHANGED, { frag: fragPlayingCurrent });
					if (!fragPlaying || fragPlaying.level !== fragCurrentLevel) this.hls.trigger(Events.LEVEL_SWITCHED, { level: fragCurrentLevel });
				}
			}
		}
	}
	get nextLevel() {
		const frag = this.nextBufferedFrag;
		if (frag) return frag.level;
		return -1;
	}
	get currentFrag() {
		var _this$media2;
		if (this.fragPlaying) return this.fragPlaying;
		const currentTime = ((_this$media2 = this.media) == null ? void 0 : _this$media2.currentTime) || this.lastCurrentTime;
		if (isFiniteNumber(currentTime)) return this.getAppendedFrag(currentTime);
		return null;
	}
	get currentProgramDateTime() {
		var _this$media3;
		const currentTime = ((_this$media3 = this.media) == null ? void 0 : _this$media3.currentTime) || this.lastCurrentTime;
		if (isFiniteNumber(currentTime)) {
			const details = this.getLevelDetails();
			const frag = this.currentFrag || (details ? findFragmentByPTS(null, details.fragments, currentTime) : null);
			if (frag) {
				const programDateTime = frag.programDateTime;
				if (programDateTime !== null) {
					const epocMs = programDateTime + (currentTime - frag.start) * 1e3;
					return new Date(epocMs);
				}
			}
		}
		return null;
	}
	get currentLevel() {
		const frag = this.currentFrag;
		if (frag) return frag.level;
		return -1;
	}
	get nextBufferedFrag() {
		const frag = this.currentFrag;
		if (frag) return this.followingBufferedFrag(frag);
		return null;
	}
	get forceStartLoad() {
		return this._forceStartLoad;
	}
};
var KeyLoader = class extends Logger {
	constructor(config, logger) {
		super("key-loader", logger);
		this.config = void 0;
		this.keyIdToKeyInfo = {};
		this.emeController = null;
		this.config = config;
	}
	abort(type) {
		for (const id in this.keyIdToKeyInfo) {
			const loader = this.keyIdToKeyInfo[id].loader;
			if (loader) {
				var _loader$context;
				if (type && type !== ((_loader$context = loader.context) == null ? void 0 : _loader$context.frag.type)) return;
				loader.abort();
			}
		}
	}
	detach() {
		for (const id in this.keyIdToKeyInfo) {
			const keyInfo = this.keyIdToKeyInfo[id];
			if (keyInfo.mediaKeySessionContext || keyInfo.decryptdata.isCommonEncryption) delete this.keyIdToKeyInfo[id];
		}
	}
	destroy() {
		this.detach();
		for (const id in this.keyIdToKeyInfo) {
			const loader = this.keyIdToKeyInfo[id].loader;
			if (loader) loader.destroy();
		}
		this.keyIdToKeyInfo = {};
	}
	createKeyLoadError(frag, details = ErrorDetails.KEY_LOAD_ERROR, error, networkDetails, response) {
		return new LoadError({
			type: ErrorTypes.NETWORK_ERROR,
			details,
			fatal: false,
			frag,
			response,
			error,
			networkDetails
		});
	}
	loadClear(loadingFrag, encryptedFragments, startFragRequested) {
		if (this.emeController && this.config.emeEnabled && !this.emeController.getSelectedKeySystemFormats().length) {
			if (encryptedFragments.length) for (let i = 0, l = encryptedFragments.length; i < l; i++) {
				const frag = encryptedFragments[i];
				if (loadingFrag.cc <= frag.cc && (!isMediaFragment(loadingFrag) || !isMediaFragment(frag) || loadingFrag.sn < frag.sn) || !startFragRequested && i == l - 1) return this.emeController.selectKeySystemFormat(frag).then((keySystemFormat) => {
					if (!this.emeController) return;
					frag.setKeyFormat(keySystemFormat);
					const keySystem = keySystemFormatToKeySystemDomain(keySystemFormat);
					if (keySystem) return this.emeController.getKeySystemAccess([keySystem]);
				});
			}
			if (this.config.requireKeySystemAccessOnStart) {
				const keySystemsInConfig = getKeySystemsForConfig(this.config);
				if (keySystemsInConfig.length) return this.emeController.getKeySystemAccess(keySystemsInConfig);
			}
		}
		return null;
	}
	load(frag) {
		if (!frag.decryptdata && frag.encrypted && this.emeController && this.config.emeEnabled) return this.emeController.selectKeySystemFormat(frag).then((keySystemFormat) => {
			return this.loadInternal(frag, keySystemFormat);
		});
		return this.loadInternal(frag);
	}
	loadInternal(frag, keySystemFormat) {
		var _keyInfo, _keyInfo2;
		if (keySystemFormat) frag.setKeyFormat(keySystemFormat);
		const decryptdata = frag.decryptdata;
		if (!decryptdata) {
			const error = /* @__PURE__ */ new Error(keySystemFormat ? `Expected frag.decryptdata to be defined after setting format ${keySystemFormat}` : `Missing decryption data on fragment in onKeyLoading (emeEnabled with controller: ${this.emeController && this.config.emeEnabled})`);
			return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, error));
		}
		const uri = decryptdata.uri;
		if (!uri) return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, /* @__PURE__ */ new Error(`Invalid key URI: "${uri}"`)));
		const id = getKeyId(decryptdata);
		let keyInfo = this.keyIdToKeyInfo[id];
		if ((_keyInfo = keyInfo) != null && _keyInfo.decryptdata.key) {
			decryptdata.key = keyInfo.decryptdata.key;
			return Promise.resolve({
				frag,
				keyInfo
			});
		}
		if (this.emeController && (_keyInfo2 = keyInfo) != null && _keyInfo2.keyLoadPromise) switch (this.emeController.getKeyStatus(keyInfo.decryptdata)) {
			case "usable":
			case "usable-in-future": return keyInfo.keyLoadPromise.then((keyLoadedData) => {
				const { keyInfo } = keyLoadedData;
				decryptdata.key = keyInfo.decryptdata.key;
				return {
					frag,
					keyInfo
				};
			});
		}
		this.log(`${this.keyIdToKeyInfo[id] ? "Rel" : "L"}oading${decryptdata.keyId ? " keyId: " + arrayToHex(decryptdata.keyId) : ""} URI: ${decryptdata.uri} from ${frag.type} ${frag.level}`);
		keyInfo = this.keyIdToKeyInfo[id] = {
			decryptdata,
			keyLoadPromise: null,
			loader: null,
			mediaKeySessionContext: null
		};
		switch (decryptdata.method) {
			case "SAMPLE-AES":
			case "SAMPLE-AES-CENC":
			case "SAMPLE-AES-CTR":
				if (decryptdata.keyFormat === "identity") return this.loadKeyHTTP(keyInfo, frag);
				return this.loadKeyEME(keyInfo, frag);
			case "AES-128":
			case "AES-256":
			case "AES-256-CTR": return this.loadKeyHTTP(keyInfo, frag);
			default: return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, /* @__PURE__ */ new Error(`Key supplied with unsupported METHOD: "${decryptdata.method}"`)));
		}
	}
	loadKeyEME(keyInfo, frag) {
		const keyLoadedData = {
			frag,
			keyInfo
		};
		if (this.emeController && this.config.emeEnabled) {
			var _frag$initSegment;
			if (!keyInfo.decryptdata.keyId && (_frag$initSegment = frag.initSegment) != null && _frag$initSegment.data) {
				const keyIds = parseKeyIdsFromTenc(frag.initSegment.data);
				if (keyIds.length) {
					let keyId = keyIds[0];
					if (keyId.some((b) => b !== 0)) {
						this.log(`Using keyId found in init segment ${arrayToHex(keyId)}`);
						LevelKey.setKeyIdForUri(keyInfo.decryptdata.uri, keyId);
					} else {
						keyId = LevelKey.addKeyIdForUri(keyInfo.decryptdata.uri);
						this.log(`Generating keyId to patch media ${arrayToHex(keyId)}`);
					}
					keyInfo.decryptdata.keyId = keyId;
				}
			}
			if (!keyInfo.decryptdata.keyId && !isMediaFragment(frag)) return Promise.resolve(keyLoadedData);
			return (keyInfo.keyLoadPromise = this.emeController.loadKey(keyLoadedData).then((keySessionContext) => {
				keyInfo.mediaKeySessionContext = keySessionContext;
				return keyLoadedData;
			})).catch((error) => {
				keyInfo.keyLoadPromise = null;
				if ("data" in error) error.data.frag = frag;
				throw error;
			});
		}
		return Promise.resolve(keyLoadedData);
	}
	loadKeyHTTP(keyInfo, frag) {
		const config = this.config;
		const Loader = config.loader;
		const keyLoader = new Loader(config);
		frag.keyLoader = keyInfo.loader = keyLoader;
		return keyInfo.keyLoadPromise = new Promise((resolve, reject) => {
			const loaderContext = {
				keyInfo,
				frag,
				responseType: "arraybuffer",
				url: keyInfo.decryptdata.uri
			};
			const loadPolicy = config.keyLoadPolicy.default;
			const loaderConfig = {
				loadPolicy,
				timeout: loadPolicy.maxLoadTimeMs,
				maxRetry: 0,
				retryDelay: 0,
				maxRetryDelay: 0
			};
			keyLoader.load(loaderContext, loaderConfig, {
				onSuccess: (response, stats, context, networkDetails) => {
					const { frag, keyInfo } = context;
					const id = getKeyId(keyInfo.decryptdata);
					if (!frag.decryptdata || keyInfo !== this.keyIdToKeyInfo[id]) return reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, /* @__PURE__ */ new Error("after key load, decryptdata unset or changed"), networkDetails));
					keyInfo.decryptdata.key = frag.decryptdata.key = new Uint8Array(response.data);
					frag.keyLoader = null;
					keyInfo.loader = null;
					resolve({
						frag,
						keyInfo
					});
				},
				onError: (response, context, networkDetails, stats) => {
					this.resetLoader(context);
					reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, /* @__PURE__ */ new Error(`HTTP Error ${response.code} loading key ${response.text}`), networkDetails, _objectSpread2({
						url: loaderContext.url,
						data: void 0
					}, response)));
				},
				onTimeout: (stats, context, networkDetails) => {
					this.resetLoader(context);
					reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_TIMEOUT, /* @__PURE__ */ new Error("key loading timed out"), networkDetails));
				},
				onAbort: (stats, context, networkDetails) => {
					this.resetLoader(context);
					reject(this.createKeyLoadError(frag, ErrorDetails.INTERNAL_ABORTED, /* @__PURE__ */ new Error("key loading aborted"), networkDetails));
				}
			});
		});
	}
	resetLoader(context) {
		const { frag, keyInfo, url: uri } = context;
		const loader = keyInfo.loader;
		if (frag.keyLoader === loader) {
			frag.keyLoader = null;
			keyInfo.loader = null;
		}
		const id = getKeyId(keyInfo.decryptdata) || uri;
		delete this.keyIdToKeyInfo[id];
		if (loader) loader.destroy();
	}
};
function getKeyId(decryptdata) {
	if (decryptdata.keyFormat !== KeySystemFormats.FAIRPLAY) {
		const keyId = decryptdata.keyId;
		if (keyId) return arrayToHex(keyId);
	}
	return decryptdata.uri;
}
function mapContextToLevelType(context) {
	const { type } = context;
	switch (type) {
		case PlaylistContextType.AUDIO_TRACK: return PlaylistLevelType.AUDIO;
		case PlaylistContextType.SUBTITLE_TRACK: return PlaylistLevelType.SUBTITLE;
		default: return PlaylistLevelType.MAIN;
	}
}
function getResponseUrl(response, context) {
	let url = response.url;
	if (url === void 0 || url.indexOf("data:") === 0) url = context.url;
	return url;
}
var PlaylistLoader = class {
	constructor(hls) {
		this.hls = void 0;
		this.loaders = Object.create(null);
		this.variableList = null;
		this.onManifestLoaded = this.checkAutostartLoad;
		this.hls = hls;
		this.registerListeners();
	}
	startLoad(startPosition) {}
	stopLoad() {
		this.destroyInternalLoaders();
	}
	registerListeners() {
		const { hls } = this;
		hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
		hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
		hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
		hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
	}
	unregisterListeners() {
		const { hls } = this;
		hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
		hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
		hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
		hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
		hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
	}
	/**
	* Returns defaults or configured loader-type overloads (pLoader and loader config params)
	*/
	createInternalLoader(context) {
		const config = this.hls.config;
		const PLoader = config.pLoader;
		const Loader = config.loader;
		const loader = new (PLoader || Loader)(config);
		this.loaders[context.type] = loader;
		return loader;
	}
	getInternalLoader(context) {
		return this.loaders[context.type];
	}
	resetInternalLoader(contextType) {
		if (this.loaders[contextType]) delete this.loaders[contextType];
	}
	/**
	* Call `destroy` on all internal loader instances mapped (one per context type)
	*/
	destroyInternalLoaders() {
		for (const contextType in this.loaders) {
			const loader = this.loaders[contextType];
			if (loader) loader.destroy();
			this.resetInternalLoader(contextType);
		}
	}
	destroy() {
		this.variableList = null;
		this.unregisterListeners();
		this.destroyInternalLoaders();
	}
	onManifestLoading(event, data) {
		const { url } = data;
		this.variableList = null;
		this.load({
			id: null,
			level: 0,
			responseType: "text",
			type: PlaylistContextType.MANIFEST,
			url,
			deliveryDirectives: null,
			levelOrTrack: null
		});
	}
	onLevelLoading(event, data) {
		const { id, level, pathwayId, url, deliveryDirectives, levelInfo } = data;
		this.load({
			id,
			level,
			pathwayId,
			responseType: "text",
			type: PlaylistContextType.LEVEL,
			url,
			deliveryDirectives,
			levelOrTrack: levelInfo
		});
	}
	onAudioTrackLoading(event, data) {
		const { id, groupId, url, deliveryDirectives, track } = data;
		this.load({
			id,
			groupId,
			level: null,
			responseType: "text",
			type: PlaylistContextType.AUDIO_TRACK,
			url,
			deliveryDirectives,
			levelOrTrack: track
		});
	}
	onSubtitleTrackLoading(event, data) {
		const { id, groupId, url, deliveryDirectives, track } = data;
		this.load({
			id,
			groupId,
			level: null,
			responseType: "text",
			type: PlaylistContextType.SUBTITLE_TRACK,
			url,
			deliveryDirectives,
			levelOrTrack: track
		});
	}
	onLevelsUpdated(event, data) {
		const loader = this.loaders[PlaylistContextType.LEVEL];
		if (loader) {
			const context = loader.context;
			if (context && !data.levels.some((lvl) => lvl === context.levelOrTrack)) {
				loader.abort();
				delete this.loaders[PlaylistContextType.LEVEL];
			}
		}
	}
	load(context) {
		var _context$deliveryDire;
		const config = this.hls.config;
		let loader = this.getInternalLoader(context);
		if (loader) {
			const logger = this.hls.logger;
			const loaderContext = loader.context;
			if (loaderContext && loaderContext.levelOrTrack === context.levelOrTrack && (loaderContext.url === context.url || loaderContext.deliveryDirectives && !context.deliveryDirectives)) {
				if (loaderContext.url === context.url) logger.log(`[playlist-loader]: ignore ${context.url} ongoing request`);
				else logger.log(`[playlist-loader]: ignore ${context.url} in favor of ${loaderContext.url}`);
				return;
			}
			logger.log(`[playlist-loader]: aborting previous loader for type: ${context.type}`);
			loader.abort();
		}
		let loadPolicy;
		if (context.type === PlaylistContextType.MANIFEST) loadPolicy = config.manifestLoadPolicy.default;
		else loadPolicy = _extends({}, config.playlistLoadPolicy.default, {
			timeoutRetry: null,
			errorRetry: null
		});
		loader = this.createInternalLoader(context);
		if (isFiniteNumber((_context$deliveryDire = context.deliveryDirectives) == null ? void 0 : _context$deliveryDire.part)) {
			let levelDetails;
			if (context.type === PlaylistContextType.LEVEL && context.level !== null) levelDetails = this.hls.levels[context.level].details;
			else if (context.type === PlaylistContextType.AUDIO_TRACK && context.id !== null) levelDetails = this.hls.audioTracks[context.id].details;
			else if (context.type === PlaylistContextType.SUBTITLE_TRACK && context.id !== null) levelDetails = this.hls.subtitleTracks[context.id].details;
			if (levelDetails) {
				const partTarget = levelDetails.partTarget;
				const targetDuration = levelDetails.targetduration;
				if (partTarget && targetDuration) {
					const maxLowLatencyPlaylistRefresh = Math.max(partTarget * 3, targetDuration * .8) * 1e3;
					loadPolicy = _extends({}, loadPolicy, {
						maxTimeToFirstByteMs: Math.min(maxLowLatencyPlaylistRefresh, loadPolicy.maxTimeToFirstByteMs),
						maxLoadTimeMs: Math.min(maxLowLatencyPlaylistRefresh, loadPolicy.maxTimeToFirstByteMs)
					});
				}
			}
		}
		const legacyRetryCompatibility = loadPolicy.errorRetry || loadPolicy.timeoutRetry || {};
		const loaderConfig = {
			loadPolicy,
			timeout: loadPolicy.maxLoadTimeMs,
			maxRetry: legacyRetryCompatibility.maxNumRetry || 0,
			retryDelay: legacyRetryCompatibility.retryDelayMs || 0,
			maxRetryDelay: legacyRetryCompatibility.maxRetryDelayMs || 0
		};
		loader.load(context, loaderConfig, {
			onSuccess: (response, stats, context, networkDetails) => {
				const loader = this.getInternalLoader(context);
				this.resetInternalLoader(context.type);
				const string = response.data;
				stats.parsing.start = performance.now();
				if (M3U8Parser.isMediaPlaylist(string) || context.type !== PlaylistContextType.MANIFEST) this.handleTrackOrLevelPlaylist(response, stats, context, networkDetails || null, loader);
				else this.handleMasterPlaylist(response, stats, context, networkDetails);
			},
			onError: (response, context, networkDetails, stats) => {
				this.handleNetworkError(context, networkDetails, false, response, stats);
			},
			onTimeout: (stats, context, networkDetails) => {
				this.handleNetworkError(context, networkDetails, true, void 0, stats);
			}
		});
	}
	checkAutostartLoad() {
		if (!this.hls) return;
		const { config: { autoStartLoad, startPosition }, forceStartLoad } = this.hls;
		if (autoStartLoad || forceStartLoad) {
			this.hls.logger.log(`${autoStartLoad ? "auto" : "force"} startLoad with configured startPosition ${startPosition}`);
			this.hls.startLoad(startPosition);
		}
	}
	handleMasterPlaylist(response, stats, context, networkDetails) {
		const hls = this.hls;
		const string = response.data;
		const url = getResponseUrl(response, context);
		const parsedResult = M3U8Parser.parseMasterPlaylist(string, url);
		if (parsedResult.playlistParsingError) {
			stats.parsing.end = performance.now();
			this.handleManifestParsingError(response, context, parsedResult.playlistParsingError, networkDetails, stats);
			return;
		}
		const { contentSteering, levels, sessionData, sessionKeys, startTimeOffset, variableList } = parsedResult;
		this.variableList = variableList;
		levels.forEach((levelParsed) => {
			const { unknownCodecs } = levelParsed;
			if (unknownCodecs) {
				const { preferManagedMediaSource } = this.hls.config;
				let { audioCodec, videoCodec } = levelParsed;
				for (let i = unknownCodecs.length; i--;) {
					const unknownCodec = unknownCodecs[i];
					if (areCodecsMediaSourceSupported(unknownCodec, "audio", preferManagedMediaSource)) {
						levelParsed.audioCodec = audioCodec = audioCodec ? `${audioCodec},${unknownCodec}` : unknownCodec;
						sampleEntryCodesISO.audio[audioCodec.substring(0, 4)] = 2;
						unknownCodecs.splice(i, 1);
					} else if (areCodecsMediaSourceSupported(unknownCodec, "video", preferManagedMediaSource)) {
						levelParsed.videoCodec = videoCodec = videoCodec ? `${videoCodec},${unknownCodec}` : unknownCodec;
						sampleEntryCodesISO.video[videoCodec.substring(0, 4)] = 2;
						unknownCodecs.splice(i, 1);
					}
				}
			}
		});
		const { AUDIO: audioTracks = [], SUBTITLES: subtitles, "CLOSED-CAPTIONS": captions } = M3U8Parser.parseMasterPlaylistMedia(string, url, parsedResult);
		if (audioTracks.length) {
			if (!audioTracks.some((audioTrack) => !audioTrack.url) && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
				this.hls.logger.log("[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one");
				audioTracks.unshift({
					type: "main",
					name: "main",
					groupId: "main",
					default: false,
					autoselect: false,
					forced: false,
					id: -1,
					attrs: new AttrList({}),
					bitrate: 0,
					url: ""
				});
			}
		}
		hls.trigger(Events.MANIFEST_LOADED, {
			levels,
			audioTracks,
			subtitles,
			captions,
			contentSteering,
			url,
			stats,
			networkDetails,
			sessionData,
			sessionKeys,
			startTimeOffset,
			variableList
		});
	}
	handleTrackOrLevelPlaylist(response, stats, context, networkDetails, loader) {
		const hls = this.hls;
		const { id, level, type } = context;
		const url = getResponseUrl(response, context);
		const levelId = isFiniteNumber(level) ? level : isFiniteNumber(id) ? id : 0;
		const levelType = mapContextToLevelType(context);
		const levelDetails = M3U8Parser.parseLevelPlaylist(response.data, url, levelId, levelType, 0, this.variableList);
		if (type === PlaylistContextType.MANIFEST) {
			const singleLevel = {
				attrs: new AttrList({}),
				bitrate: 0,
				details: levelDetails,
				name: "",
				url
			};
			levelDetails.requestScheduled = stats.loading.start + computeReloadInterval(levelDetails, 0);
			hls.trigger(Events.MANIFEST_LOADED, {
				levels: [singleLevel],
				audioTracks: [],
				url,
				stats,
				networkDetails,
				sessionData: null,
				sessionKeys: null,
				contentSteering: null,
				startTimeOffset: null,
				variableList: null
			});
		}
		stats.parsing.end = performance.now();
		context.levelDetails = levelDetails;
		this.handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader);
	}
	handleManifestParsingError(response, context, error, networkDetails, stats) {
		this.hls.trigger(Events.ERROR, {
			type: ErrorTypes.NETWORK_ERROR,
			details: ErrorDetails.MANIFEST_PARSING_ERROR,
			fatal: context.type === PlaylistContextType.MANIFEST,
			url: response.url,
			err: error,
			error,
			reason: error.message,
			response,
			context,
			networkDetails,
			stats
		});
	}
	handleNetworkError(context, networkDetails, timeout = false, response, stats) {
		let message = `A network ${timeout ? "timeout" : "error" + (response ? " (status " + response.code + ")" : "")} occurred while loading ${context.type}`;
		if (context.type === PlaylistContextType.LEVEL) message += `: ${context.level} id: ${context.id}`;
		else if (context.type === PlaylistContextType.AUDIO_TRACK || context.type === PlaylistContextType.SUBTITLE_TRACK) message += ` id: ${context.id} group-id: "${context.groupId}"`;
		const error = new Error(message);
		this.hls.logger.warn(`[playlist-loader]: ${message}`);
		let details = ErrorDetails.UNKNOWN;
		let fatal = false;
		const loader = this.getInternalLoader(context);
		switch (context.type) {
			case PlaylistContextType.MANIFEST:
				details = timeout ? ErrorDetails.MANIFEST_LOAD_TIMEOUT : ErrorDetails.MANIFEST_LOAD_ERROR;
				fatal = true;
				break;
			case PlaylistContextType.LEVEL:
				details = timeout ? ErrorDetails.LEVEL_LOAD_TIMEOUT : ErrorDetails.LEVEL_LOAD_ERROR;
				fatal = false;
				break;
			case PlaylistContextType.AUDIO_TRACK:
				details = timeout ? ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT : ErrorDetails.AUDIO_TRACK_LOAD_ERROR;
				fatal = false;
				break;
			case PlaylistContextType.SUBTITLE_TRACK:
				details = timeout ? ErrorDetails.SUBTITLE_TRACK_LOAD_TIMEOUT : ErrorDetails.SUBTITLE_LOAD_ERROR;
				fatal = false;
				break;
		}
		if (loader) this.resetInternalLoader(context.type);
		const errorData = {
			type: ErrorTypes.NETWORK_ERROR,
			details,
			fatal,
			url: context.url,
			loader,
			context,
			error,
			networkDetails,
			stats
		};
		if (response) errorData.response = _objectSpread2({
			url: (networkDetails == null ? void 0 : networkDetails.url) || context.url,
			data: void 0
		}, response);
		this.hls.trigger(Events.ERROR, errorData);
	}
	handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader) {
		const hls = this.hls;
		const { type, level, levelOrTrack, id, groupId, deliveryDirectives } = context;
		const url = getResponseUrl(response, context);
		const parent = mapContextToLevelType(context);
		let levelIndex = typeof context.level === "number" && parent === PlaylistLevelType.MAIN ? level : void 0;
		const error = levelDetails.playlistParsingError;
		if (error) {
			this.hls.logger.warn(`${error} ${levelDetails.url}`);
			if (!hls.config.ignorePlaylistParsingErrors) {
				hls.trigger(Events.ERROR, {
					type: ErrorTypes.NETWORK_ERROR,
					details: ErrorDetails.LEVEL_PARSING_ERROR,
					fatal: false,
					url,
					error,
					reason: error.message,
					response,
					context,
					level: levelIndex,
					parent,
					networkDetails,
					stats
				});
				return;
			}
			levelDetails.playlistParsingError = null;
		}
		if (!levelDetails.fragments.length) {
			const _error = levelDetails.playlistParsingError = /* @__PURE__ */ new Error("No Segments found in Playlist");
			hls.trigger(Events.ERROR, {
				type: ErrorTypes.NETWORK_ERROR,
				details: ErrorDetails.LEVEL_EMPTY_ERROR,
				fatal: false,
				url,
				error: _error,
				reason: _error.message,
				response,
				context,
				level: levelIndex,
				parent,
				networkDetails,
				stats
			});
			return;
		}
		if (levelDetails.live && loader) {
			if (loader.getCacheAge) levelDetails.ageHeader = loader.getCacheAge() || 0;
			if (!loader.getCacheAge || isNaN(levelDetails.ageHeader)) levelDetails.ageHeader = 0;
		}
		switch (type) {
			case PlaylistContextType.MANIFEST:
			case PlaylistContextType.LEVEL:
				if (levelIndex) {
					if (!levelOrTrack) levelIndex = 0;
					else if (levelOrTrack !== hls.levels[levelIndex]) {
						const updatedIndex = hls.levels.indexOf(levelOrTrack);
						if (updatedIndex > -1) levelIndex = updatedIndex;
					}
				}
				hls.trigger(Events.LEVEL_LOADED, {
					details: levelDetails,
					levelInfo: levelOrTrack || hls.levels[0],
					level: levelIndex || 0,
					id: id || 0,
					stats,
					networkDetails,
					deliveryDirectives,
					withoutMultiVariant: type === PlaylistContextType.MANIFEST
				});
				break;
			case PlaylistContextType.AUDIO_TRACK:
				hls.trigger(Events.AUDIO_TRACK_LOADED, {
					details: levelDetails,
					track: levelOrTrack,
					id: id || 0,
					groupId: groupId || "",
					stats,
					networkDetails,
					deliveryDirectives
				});
				break;
			case PlaylistContextType.SUBTITLE_TRACK:
				hls.trigger(Events.SUBTITLE_TRACK_LOADED, {
					details: levelDetails,
					track: levelOrTrack,
					id: id || 0,
					groupId: groupId || "",
					stats,
					networkDetails,
					deliveryDirectives
				});
				break;
		}
	}
};
/**
* The `Hls` class is the core of the HLS.js library used to instantiate player instances.
* @public
*/
var Hls = class Hls {
	/**
	* Get the video-dev/hls.js package version.
	*/
	static get version() {
		return version;
	}
	/**
	* Check if the required MediaSource Extensions are available.
	*/
	static isMSESupported() {
		return isMSESupported();
	}
	/**
	* Check if MediaSource Extensions are available and isTypeSupported checks pass for any baseline codecs.
	*/
	static isSupported() {
		return isSupported();
	}
	/**
	* Get the MediaSource global used for MSE playback (ManagedMediaSource, MediaSource, or WebKitMediaSource).
	*/
	static getMediaSource() {
		return getMediaSource();
	}
	static get Events() {
		return Events;
	}
	static get MetadataSchema() {
		return MetadataSchema;
	}
	static get ErrorTypes() {
		return ErrorTypes;
	}
	static get ErrorDetails() {
		return ErrorDetails;
	}
	/**
	* Get the default configuration applied to new instances.
	*/
	static get DefaultConfig() {
		if (!Hls.defaultConfig) return hlsDefaultConfig;
		return Hls.defaultConfig;
	}
	/**
	* Replace the default configuration applied to new instances.
	*/
	static set DefaultConfig(defaultConfig) {
		Hls.defaultConfig = defaultConfig;
	}
	/**
	* Creates an instance of an HLS client that can attach to exactly one `HTMLMediaElement`.
	* @param userConfig - Configuration options applied over `Hls.DefaultConfig`
	*/
	constructor(userConfig = {}) {
		/**
		* The runtime configuration used by the player. At instantiation this is combination of `hls.userConfig` merged over `Hls.DefaultConfig`.
		*/
		this.config = void 0;
		/**
		* The configuration object provided on player instantiation.
		*/
		this.userConfig = void 0;
		/**
		* The logger functions used by this player instance, configured on player instantiation.
		*/
		this.logger = void 0;
		this.coreComponents = void 0;
		this.networkControllers = void 0;
		this._emitter = new EventEmitter();
		this._autoLevelCapping = -1;
		this._maxHdcpLevel = null;
		this.abrController = void 0;
		this.bufferController = void 0;
		this.capLevelController = void 0;
		this.latencyController = void 0;
		this.levelController = void 0;
		this.streamController = void 0;
		this.audioStreamController = void 0;
		this.subtititleStreamController = void 0;
		this.audioTrackController = void 0;
		this.subtitleTrackController = void 0;
		this.interstitialsController = void 0;
		this.gapController = void 0;
		this.emeController = void 0;
		this.cmcdController = void 0;
		this._media = null;
		this._url = null;
		this._sessionId = void 0;
		this.triggeringException = void 0;
		this.started = false;
		const logger = this.logger = enableLogs(userConfig.debug || false, "Hls instance", userConfig.assetPlayerId);
		const config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
		this.userConfig = userConfig;
		if (config.progressive) enableStreamingMode(config, logger);
		const { abrController: _AbrController, bufferController: _BufferController, capLevelController: _CapLevelController, errorController: _ErrorController, fpsController: _FpsController } = config;
		const errorController = new _ErrorController(this);
		const abrController = this.abrController = new _AbrController(this);
		const fragmentTracker = new FragmentTracker(this);
		const _InterstitialsController = config.interstitialsController;
		const interstitialsController = _InterstitialsController ? this.interstitialsController = new _InterstitialsController(this, Hls) : null;
		const bufferController = this.bufferController = new _BufferController(this, fragmentTracker);
		const capLevelController = this.capLevelController = new _CapLevelController(this);
		const fpsController = new _FpsController(this);
		const playListLoader = new PlaylistLoader(this);
		const _ContentSteeringController = config.contentSteeringController;
		const contentSteering = _ContentSteeringController ? new _ContentSteeringController(this) : null;
		const levelController = this.levelController = new LevelController(this, contentSteering);
		const id3TrackController = new ID3TrackController(this);
		const keyLoader = new KeyLoader(this.config, this.logger);
		const streamController = this.streamController = new StreamController(this, fragmentTracker, keyLoader);
		const gapController = this.gapController = new GapController(this, fragmentTracker);
		capLevelController.setStreamController(streamController);
		fpsController.setStreamController(streamController);
		const networkControllers = [
			playListLoader,
			levelController,
			streamController
		];
		if (interstitialsController) networkControllers.splice(1, 0, interstitialsController);
		if (contentSteering) networkControllers.splice(1, 0, contentSteering);
		this.networkControllers = networkControllers;
		const coreComponents = [
			abrController,
			bufferController,
			gapController,
			capLevelController,
			fpsController,
			id3TrackController,
			fragmentTracker
		];
		this.audioTrackController = this.createController(config.audioTrackController, networkControllers);
		const AudioStreamControllerClass = config.audioStreamController;
		if (AudioStreamControllerClass) networkControllers.push(this.audioStreamController = new AudioStreamControllerClass(this, fragmentTracker, keyLoader));
		this.subtitleTrackController = this.createController(config.subtitleTrackController, networkControllers);
		const SubtitleStreamControllerClass = config.subtitleStreamController;
		if (SubtitleStreamControllerClass) networkControllers.push(this.subtititleStreamController = new SubtitleStreamControllerClass(this, fragmentTracker, keyLoader));
		this.createController(config.timelineController, coreComponents);
		keyLoader.emeController = this.emeController = this.createController(config.emeController, coreComponents);
		this.cmcdController = this.createController(config.cmcdController, coreComponents);
		this.latencyController = this.createController(LatencyController, coreComponents);
		this.coreComponents = coreComponents;
		networkControllers.push(errorController);
		const onErrorOut = errorController.onErrorOut;
		if (typeof onErrorOut === "function") this.on(Events.ERROR, onErrorOut, errorController);
		this.on(Events.MANIFEST_LOADED, playListLoader.onManifestLoaded, playListLoader);
	}
	createController(ControllerClass, components) {
		if (ControllerClass) {
			const controllerInstance = new ControllerClass(this);
			if (components) components.push(controllerInstance);
			return controllerInstance;
		}
		return null;
	}
	on(event, listener, context = this) {
		this._emitter.on(event, listener, context);
	}
	once(event, listener, context = this) {
		this._emitter.once(event, listener, context);
	}
	removeAllListeners(event) {
		this._emitter.removeAllListeners(event);
	}
	off(event, listener, context = this, once) {
		this._emitter.off(event, listener, context, once);
	}
	listeners(event) {
		return this._emitter.listeners(event);
	}
	emit(event, name, eventObject) {
		return this._emitter.emit(event, name, eventObject);
	}
	trigger(event, eventObject) {
		if (this.config.debug) return this.emit(event, event, eventObject);
		else try {
			return this.emit(event, event, eventObject);
		} catch (error) {
			this.logger.error("An internal error happened while handling event " + event + ". Error message: \"" + error.message + "\". Here is a stacktrace:", error);
			if (!this.triggeringException) {
				this.triggeringException = true;
				const fatal = event === Events.ERROR;
				this.trigger(Events.ERROR, {
					type: ErrorTypes.OTHER_ERROR,
					details: ErrorDetails.INTERNAL_EXCEPTION,
					fatal,
					event,
					error
				});
				this.triggeringException = false;
			}
		}
		return false;
	}
	listenerCount(event) {
		return this._emitter.listenerCount(event);
	}
	/**
	* Dispose of the instance
	*/
	destroy() {
		this.logger.log("destroy");
		this.trigger(Events.DESTROYING, void 0);
		this.detachMedia();
		this.removeAllListeners();
		this._autoLevelCapping = -1;
		this._url = null;
		this.networkControllers.forEach((component) => component.destroy());
		this.networkControllers.length = 0;
		this.coreComponents.forEach((component) => component.destroy());
		this.coreComponents.length = 0;
		const config = this.config;
		config.xhrSetup = config.fetchSetup = void 0;
		this.userConfig = null;
	}
	/**
	* Attaches Hls.js to a media element
	*/
	attachMedia(data) {
		if (!data || "media" in data && !data.media) {
			const error = /* @__PURE__ */ new Error(`attachMedia failed: invalid argument (${data})`);
			this.trigger(Events.ERROR, {
				type: ErrorTypes.OTHER_ERROR,
				details: ErrorDetails.ATTACH_MEDIA_ERROR,
				fatal: true,
				error
			});
			return;
		}
		this.logger.log(`attachMedia`);
		if (this._media) {
			this.logger.warn(`media must be detached before attaching`);
			this.detachMedia();
		}
		const attachMediaSource = "media" in data;
		const media = attachMediaSource ? data.media : data;
		const attachingData = attachMediaSource ? data : { media };
		this._media = media;
		this.trigger(Events.MEDIA_ATTACHING, attachingData);
	}
	/**
	* Detach Hls.js from the media
	*/
	detachMedia() {
		this.logger.log("detachMedia");
		this.trigger(Events.MEDIA_DETACHING, {});
		this._media = null;
	}
	/**
	* Detach HTMLMediaElement, MediaSource, and SourceBuffers without reset, for attaching to another instance
	*/
	transferMedia() {
		this._media = null;
		const transferMedia = this.bufferController.transferMedia();
		this.trigger(Events.MEDIA_DETACHING, { transferMedia });
		return transferMedia;
	}
	/**
	* Set the source URL. Can be relative or absolute.
	*/
	loadSource(url) {
		this.stopLoad();
		const media = this.media;
		const loadedSource = this._url;
		const loadingSource = this._url = urlToolkitExports.buildAbsoluteURL(self.location.href, url, { alwaysNormalize: true });
		this._autoLevelCapping = -1;
		this._maxHdcpLevel = null;
		this.logger.log(`loadSource:${loadingSource}`);
		if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
			this.detachMedia();
			this.attachMedia(media);
		}
		this.trigger(Events.MANIFEST_LOADING, { url });
	}
	/**
	* Gets the currently loaded URL
	*/
	get url() {
		return this._url;
	}
	/**
	* Whether or not enough has been buffered to seek to start position or use `media.currentTime` to determine next load position
	*/
	get hasEnoughToStart() {
		return this.streamController.hasEnoughToStart;
	}
	/**
	* Get the startPosition set on startLoad(position) or on autostart with config.startPosition
	*/
	get startPosition() {
		return this.streamController.startPositionValue;
	}
	/**
	* Start loading data from the stream source.
	* Depending on default config, client starts loading automatically when a source is set.
	*
	* @param startPosition - Set the start position to stream from.
	* Defaults to -1 (None: starts from earliest point)
	*/
	startLoad(startPosition = -1, skipSeekToStartPosition) {
		this.logger.log(`startLoad(${startPosition + (skipSeekToStartPosition ? ", " : "")})`);
		this.started = true;
		this.resumeBuffering();
		for (let i = 0; i < this.networkControllers.length; i++) {
			this.networkControllers[i].startLoad(startPosition, skipSeekToStartPosition);
			if (!this.started || !this.networkControllers) break;
		}
	}
	/**
	* Stop loading of any stream data.
	*/
	stopLoad() {
		this.logger.log("stopLoad");
		this.started = false;
		for (let i = 0; i < this.networkControllers.length; i++) {
			this.networkControllers[i].stopLoad();
			if (this.started || !this.networkControllers) break;
		}
	}
	/**
	* Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
	*/
	get loadingEnabled() {
		return this.started;
	}
	/**
	* Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
	*/
	get bufferingEnabled() {
		return this.streamController.bufferingEnabled;
	}
	/**
	* Resumes stream controller segment loading after `pauseBuffering` has been called.
	*/
	resumeBuffering() {
		if (!this.bufferingEnabled) {
			this.logger.log(`resume buffering`);
			this.networkControllers.forEach((controller) => {
				if (controller.resumeBuffering) controller.resumeBuffering();
			});
		}
	}
	/**
	* Prevents stream controller from loading new segments until `resumeBuffering` is called.
	* This allows for media buffering to be paused without interupting playlist loading.
	*/
	pauseBuffering() {
		if (this.bufferingEnabled) {
			this.logger.log(`pause buffering`);
			this.networkControllers.forEach((controller) => {
				if (controller.pauseBuffering) controller.pauseBuffering();
			});
		}
	}
	get inFlightFragments() {
		const inFlightData = { [PlaylistLevelType.MAIN]: this.streamController.inFlightFrag };
		if (this.audioStreamController) inFlightData[PlaylistLevelType.AUDIO] = this.audioStreamController.inFlightFrag;
		if (this.subtititleStreamController) inFlightData[PlaylistLevelType.SUBTITLE] = this.subtititleStreamController.inFlightFrag;
		return inFlightData;
	}
	/**
	* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
	*/
	swapAudioCodec() {
		this.logger.log("swapAudioCodec");
		this.streamController.swapAudioCodec();
	}
	/**
	* When the media-element fails, this allows to detach and then re-attach it
	* as one call (convenience method).
	*
	* Automatic recovery of media-errors by this process is configurable.
	*/
	recoverMediaError() {
		this.logger.log("recoverMediaError");
		const media = this._media;
		const time = media == null ? void 0 : media.currentTime;
		this.detachMedia();
		if (media) {
			this.attachMedia(media);
			if (time) this.startLoad(time);
		}
	}
	removeLevel(levelIndex) {
		this.levelController.removeLevel(levelIndex);
	}
	/**
	* @returns a UUID for this player instance
	*/
	get sessionId() {
		let _sessionId = this._sessionId;
		if (!_sessionId) _sessionId = this._sessionId = uuid();
		return _sessionId;
	}
	/**
	* @returns an array of levels (variants) sorted by HDCP-LEVEL, RESOLUTION (height), FRAME-RATE, CODECS, VIDEO-RANGE, and BANDWIDTH
	*/
	get levels() {
		const levels = this.levelController.levels;
		return levels ? levels : [];
	}
	/**
	* @returns LevelDetails of last loaded level (variant) or `null` prior to loading a media playlist.
	*/
	get latestLevelDetails() {
		return this.streamController.getLevelDetails() || null;
	}
	/**
	* @returns Level object of selected level (variant) or `null` prior to selecting a level or once the level is removed.
	*/
	get loadLevelObj() {
		return this.levelController.loadLevelObj;
	}
	/**
	* Index of quality level (variant) currently played
	*/
	get currentLevel() {
		return this.streamController.currentLevel;
	}
	/**
	* Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
	*/
	set currentLevel(newLevel) {
		this.logger.log(`set currentLevel:${newLevel}`);
		this.levelController.manualLevel = newLevel;
		this.streamController.immediateLevelSwitch();
	}
	/**
	* Index of next quality level loaded as scheduled by stream controller.
	*/
	get nextLevel() {
		return this.streamController.nextLevel;
	}
	/**
	* Set quality level index for next loaded data.
	* This will switch the video quality asap, without interrupting playback.
	* May abort current loading of data, and flush parts of buffer (outside currently played fragment region).
	* @param newLevel - Pass -1 for automatic level selection
	*/
	set nextLevel(newLevel) {
		this.logger.log(`set nextLevel:${newLevel}`);
		this.levelController.manualLevel = newLevel;
		this.streamController.nextLevelSwitch();
	}
	/**
	* Return the quality level of the currently or last (of none is loaded currently) segment
	*/
	get loadLevel() {
		return this.levelController.level;
	}
	/**
	* Set quality level index for next loaded data in a conservative way.
	* This will switch the quality without flushing, but interrupt current loading.
	* Thus the moment when the quality switch will appear in effect will only be after the already existing buffer.
	* @param newLevel - Pass -1 for automatic level selection
	*/
	set loadLevel(newLevel) {
		this.logger.log(`set loadLevel:${newLevel}`);
		this.levelController.manualLevel = newLevel;
	}
	/**
	* get next quality level loaded
	*/
	get nextLoadLevel() {
		return this.levelController.nextLoadLevel;
	}
	/**
	* Set quality level of next loaded segment in a fully "non-destructive" way.
	* Same as `loadLevel` but will wait for next switch (until current loading is done).
	*/
	set nextLoadLevel(level) {
		this.levelController.nextLoadLevel = level;
	}
	/**
	* Return "first level": like a default level, if not set,
	* falls back to index of first level referenced in manifest
	*/
	get firstLevel() {
		return Math.max(this.levelController.firstLevel, this.minAutoLevel);
	}
	/**
	* Sets "first-level", see getter.
	*/
	set firstLevel(newLevel) {
		this.logger.log(`set firstLevel:${newLevel}`);
		this.levelController.firstLevel = newLevel;
	}
	/**
	* Return the desired start level for the first fragment that will be loaded.
	* The default value of -1 indicates automatic start level selection.
	* Setting hls.nextAutoLevel without setting a startLevel will result in
	* the nextAutoLevel value being used for one fragment load.
	*/
	get startLevel() {
		const startLevel = this.levelController.startLevel;
		if (startLevel === -1 && this.abrController.forcedAutoLevel > -1) return this.abrController.forcedAutoLevel;
		return startLevel;
	}
	/**
	* set  start level (level of first fragment that will be played back)
	* if not overrided by user, first level appearing in manifest will be used as start level
	* if -1 : automatic start level selection, playback will start from level matching download bandwidth
	* (determined from download of first segment)
	*/
	set startLevel(newLevel) {
		this.logger.log(`set startLevel:${newLevel}`);
		if (newLevel !== -1) newLevel = Math.max(newLevel, this.minAutoLevel);
		this.levelController.startLevel = newLevel;
	}
	/**
	* Whether level capping is enabled.
	* Default value is set via `config.capLevelToPlayerSize`.
	*/
	get capLevelToPlayerSize() {
		return this.config.capLevelToPlayerSize;
	}
	/**
	* Enables or disables level capping. If disabled after previously enabled, `nextLevelSwitch` will be immediately called.
	*/
	set capLevelToPlayerSize(shouldStartCapping) {
		const newCapLevelToPlayerSize = !!shouldStartCapping;
		if (newCapLevelToPlayerSize !== this.config.capLevelToPlayerSize) {
			if (newCapLevelToPlayerSize) this.capLevelController.startCapping();
			else {
				this.capLevelController.stopCapping();
				this.autoLevelCapping = -1;
				this.streamController.nextLevelSwitch();
			}
			this.config.capLevelToPlayerSize = newCapLevelToPlayerSize;
		}
	}
	/**
	* Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
	*/
	get autoLevelCapping() {
		return this._autoLevelCapping;
	}
	/**
	* Returns the current bandwidth estimate in bits per second, when available. Otherwise, `NaN` is returned.
	*/
	get bandwidthEstimate() {
		const { bwEstimator } = this.abrController;
		if (!bwEstimator) return NaN;
		return bwEstimator.getEstimate();
	}
	set bandwidthEstimate(abrEwmaDefaultEstimate) {
		this.abrController.resetEstimator(abrEwmaDefaultEstimate);
	}
	get abrEwmaDefaultEstimate() {
		const { bwEstimator } = this.abrController;
		if (!bwEstimator) return NaN;
		return bwEstimator.defaultEstimate;
	}
	/**
	* get time to first byte estimate
	* @type {number}
	*/
	get ttfbEstimate() {
		const { bwEstimator } = this.abrController;
		if (!bwEstimator) return NaN;
		return bwEstimator.getEstimateTTFB();
	}
	/**
	* Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
	*/
	set autoLevelCapping(newLevel) {
		if (this._autoLevelCapping !== newLevel) {
			this.logger.log(`set autoLevelCapping:${newLevel}`);
			this._autoLevelCapping = newLevel;
			this.levelController.checkMaxAutoUpdated();
		}
	}
	get maxHdcpLevel() {
		return this._maxHdcpLevel;
	}
	set maxHdcpLevel(value) {
		if (isHdcpLevel(value) && this._maxHdcpLevel !== value) {
			this._maxHdcpLevel = value;
			this.levelController.checkMaxAutoUpdated();
		}
	}
	/**
	* True when automatic level selection enabled
	*/
	get autoLevelEnabled() {
		return this.levelController.manualLevel === -1;
	}
	/**
	* Level set manually (if any)
	*/
	get manualLevel() {
		return this.levelController.manualLevel;
	}
	/**
	* min level selectable in auto mode according to config.minAutoBitrate
	*/
	get minAutoLevel() {
		const { levels, config: { minAutoBitrate } } = this;
		if (!levels) return 0;
		const len = levels.length;
		for (let i = 0; i < len; i++) if (levels[i].maxBitrate >= minAutoBitrate) return i;
		return 0;
	}
	/**
	* max level selectable in auto mode according to autoLevelCapping
	*/
	get maxAutoLevel() {
		const { levels, autoLevelCapping, maxHdcpLevel } = this;
		let maxAutoLevel;
		if (autoLevelCapping === -1 && levels != null && levels.length) maxAutoLevel = levels.length - 1;
		else maxAutoLevel = autoLevelCapping;
		if (maxHdcpLevel) for (let i = maxAutoLevel; i--;) {
			const hdcpLevel = levels[i].attrs["HDCP-LEVEL"];
			if (hdcpLevel && hdcpLevel <= maxHdcpLevel) return i;
		}
		return maxAutoLevel;
	}
	get firstAutoLevel() {
		return this.abrController.firstAutoLevel;
	}
	/**
	* next automatically selected quality level
	*/
	get nextAutoLevel() {
		return this.abrController.nextAutoLevel;
	}
	/**
	* this setter is used to force next auto level.
	* this is useful to force a switch down in auto mode:
	* in case of load error on level N, hls.js can set nextAutoLevel to N-1 for example)
	* forced value is valid for one fragment. upon successful frag loading at forced level,
	* this value will be resetted to -1 by ABR controller.
	*/
	set nextAutoLevel(nextLevel) {
		this.abrController.nextAutoLevel = nextLevel;
	}
	/**
	* get the datetime value relative to media.currentTime for the active level Program Date Time if present
	*/
	get playingDate() {
		return this.streamController.currentProgramDateTime;
	}
	get mainForwardBufferInfo() {
		return this.streamController.getMainFwdBufferInfo();
	}
	get maxBufferLength() {
		return this.streamController.maxBufferLength;
	}
	/**
	* Find and select the best matching audio track, making a level switch when a Group change is necessary.
	* Updates `hls.config.audioPreference`. Returns the selected track, or null when no matching track is found.
	*/
	setAudioOption(audioOption) {
		var _this$audioTrackContr;
		return ((_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption)) || null;
	}
	/**
	* Find and select the best matching subtitle track, making a level switch when a Group change is necessary.
	* Updates `hls.config.subtitlePreference`. Returns the selected track, or null when no matching track is found.
	*/
	setSubtitleOption(subtitleOption) {
		var _this$subtitleTrackCo;
		return ((_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption)) || null;
	}
	/**
	* Get the complete list of audio tracks across all media groups
	*/
	get allAudioTracks() {
		const audioTrackController = this.audioTrackController;
		return audioTrackController ? audioTrackController.allAudioTracks : [];
	}
	/**
	* Get the list of selectable audio tracks
	*/
	get audioTracks() {
		const audioTrackController = this.audioTrackController;
		return audioTrackController ? audioTrackController.audioTracks : [];
	}
	/**
	* index of the selected audio track (index in audio track lists)
	*/
	get audioTrack() {
		const audioTrackController = this.audioTrackController;
		return audioTrackController ? audioTrackController.audioTrack : -1;
	}
	/**
	* selects an audio track, based on its index in audio track lists
	*/
	set audioTrack(audioTrackId) {
		const audioTrackController = this.audioTrackController;
		if (audioTrackController) audioTrackController.audioTrack = audioTrackId;
	}
	/**
	* get the complete list of subtitle tracks across all media groups
	*/
	get allSubtitleTracks() {
		const subtitleTrackController = this.subtitleTrackController;
		return subtitleTrackController ? subtitleTrackController.allSubtitleTracks : [];
	}
	/**
	* get alternate subtitle tracks list from playlist
	*/
	get subtitleTracks() {
		const subtitleTrackController = this.subtitleTrackController;
		return subtitleTrackController ? subtitleTrackController.subtitleTracks : [];
	}
	/**
	* index of the selected subtitle track (index in subtitle track lists)
	*/
	get subtitleTrack() {
		const subtitleTrackController = this.subtitleTrackController;
		return subtitleTrackController ? subtitleTrackController.subtitleTrack : -1;
	}
	get media() {
		return this._media;
	}
	/**
	* select an subtitle track, based on its index in subtitle track lists
	*/
	set subtitleTrack(subtitleTrackId) {
		const subtitleTrackController = this.subtitleTrackController;
		if (subtitleTrackController) subtitleTrackController.subtitleTrack = subtitleTrackId;
	}
	/**
	* Whether subtitle display is enabled or not
	*/
	get subtitleDisplay() {
		const subtitleTrackController = this.subtitleTrackController;
		return subtitleTrackController ? subtitleTrackController.subtitleDisplay : false;
	}
	/**
	* Enable/disable subtitle display rendering
	*/
	set subtitleDisplay(value) {
		const subtitleTrackController = this.subtitleTrackController;
		if (subtitleTrackController) subtitleTrackController.subtitleDisplay = value;
	}
	/**
	* get mode for Low-Latency HLS loading
	*/
	get lowLatencyMode() {
		return this.config.lowLatencyMode;
	}
	/**
	* Enable/disable Low-Latency HLS part playlist and segment loading, and start live streams at playlist PART-HOLD-BACK rather than HOLD-BACK.
	*/
	set lowLatencyMode(mode) {
		this.config.lowLatencyMode = mode;
	}
	/**
	* Position (in seconds) of live sync point (ie edge of live position minus safety delay defined by ```hls.config.liveSyncDuration```)
	* @returns null prior to loading live Playlist
	*/
	get liveSyncPosition() {
		return this.latencyController.liveSyncPosition;
	}
	/**
	* Estimated position (in seconds) of live edge (ie edge of live playlist plus time sync playlist advanced)
	* @returns 0 before first playlist is loaded
	*/
	get latency() {
		return this.latencyController.latency;
	}
	/**
	* maximum distance from the edge before the player seeks forward to ```hls.liveSyncPosition```
	* configured using ```liveMaxLatencyDurationCount``` (multiple of target duration) or ```liveMaxLatencyDuration```
	* @returns 0 before first playlist is loaded
	*/
	get maxLatency() {
		return this.latencyController.maxLatency;
	}
	/**
	* target distance from the edge as calculated by the latency controller
	*/
	get targetLatency() {
		return this.latencyController.targetLatency;
	}
	set targetLatency(latency) {
		this.latencyController.targetLatency = latency;
	}
	/**
	* the rate at which the edge of the current live playlist is advancing or 1 if there is none
	*/
	get drift() {
		return this.latencyController.drift;
	}
	/**
	* set to true when startLoad is called before MANIFEST_PARSED event
	*/
	get forceStartLoad() {
		return this.streamController.forceStartLoad;
	}
	/**
	* ContentSteering pathways getter
	*/
	get pathways() {
		return this.levelController.pathways;
	}
	/**
	* ContentSteering pathwayPriority getter/setter
	*/
	get pathwayPriority() {
		return this.levelController.pathwayPriority;
	}
	set pathwayPriority(pathwayPriority) {
		this.levelController.pathwayPriority = pathwayPriority;
	}
	/**
	* returns true when all SourceBuffers are buffered to the end
	*/
	get bufferedToEnd() {
		var _this$bufferControlle;
		return !!((_this$bufferControlle = this.bufferController) != null && _this$bufferControlle.bufferedToEnd);
	}
	/**
	* returns Interstitials Program Manager
	*/
	get interstitialsManager() {
		var _this$interstitialsCo;
		return ((_this$interstitialsCo = this.interstitialsController) == null ? void 0 : _this$interstitialsCo.interstitialsManager) || null;
	}
	/**
	* returns mediaCapabilities.decodingInfo for a variant/rendition
	*/
	getMediaDecodingInfo(level, audioTracks = this.allAudioTracks) {
		return getMediaDecodingInfoPromise(level, getAudioTracksByGroup(audioTracks), navigator.mediaCapabilities);
	}
};
Hls.defaultConfig = void 0;
//#endregion
//#region node_modules/@react-three/drei/core/VideoTexture.js
var IS_BROWSER = /* @__PURE__ */ ((_window$document, _window$navigator) => typeof window !== "undefined" && typeof ((_window$document = window.document) == null ? void 0 : _window$document.createElement) === "function" && typeof ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.userAgent) === "string")();
var _HLSModule = null;
async function getHls(...args) {
	var _HLSModule2;
	(_HLSModule2 = _HLSModule) !== null && _HLSModule2 !== void 0 || (_HLSModule = await Promise.resolve().then(() => hls_exports));
	const Ctor = _HLSModule.default;
	if (Ctor.isSupported()) return new Ctor(...args);
	return null;
}
function useVideoTexture(srcOrSrcObject, { unsuspend = "loadedmetadata", start = true, hls: hlsConfig = {}, crossOrigin = "anonymous", muted = true, loop = true, playsInline = true, onVideoFrame, ...videoProps } = {}) {
	const gl = useThree((state) => state.gl);
	const hlsRef = (0, import_react.useRef)(null);
	const texture = suspend(() => new Promise(async (res) => {
		let src = void 0;
		let srcObject = void 0;
		if (typeof srcOrSrcObject === "string") src = srcOrSrcObject;
		else srcObject = srcOrSrcObject;
		const video = Object.assign(document.createElement("video"), {
			src,
			srcObject,
			crossOrigin,
			loop,
			muted,
			playsInline,
			...videoProps
		});
		if (src && IS_BROWSER && src.endsWith(".m3u8")) {
			const hls = hlsRef.current = await getHls(hlsConfig);
			if (hls) {
				hls.on(Events.MEDIA_ATTACHED, () => void hls.loadSource(src));
				hls.attachMedia(video);
			}
		}
		const texture = new VideoTexture$1(video);
		texture.colorSpace = gl.outputColorSpace;
		video.addEventListener(unsuspend, () => res(texture));
	}), [srcOrSrcObject]);
	const video = texture.source.data;
	useVideoFrame(video, onVideoFrame);
	(0, import_react.useEffect)(() => {
		start && texture.image.play();
		return () => {
			if (hlsRef.current) {
				hlsRef.current.destroy();
				hlsRef.current = null;
			}
		};
	}, [texture, start]);
	return texture;
}
var VideoTexture = /* @__PURE__ */ (0, import_react.forwardRef)(({ children, src, ...config }, fref) => {
	const texture = useVideoTexture(src, config);
	(0, import_react.useEffect)(() => {
		return () => void texture.dispose();
	}, [texture]);
	(0, import_react.useImperativeHandle)(fref, () => texture, [texture]);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(texture));
});
var useVideoFrame = (video, f) => {
	(0, import_react.useEffect)(() => {
		if (!f) return;
		if (!video.requestVideoFrameCallback) return;
		let handle;
		const callback = (...args) => {
			f(...args);
			handle = video.requestVideoFrameCallback(callback);
		};
		video.requestVideoFrameCallback(callback);
		return () => video.cancelVideoFrameCallback(handle);
	}, [video, f]);
};
//#endregion
//#region node_modules/@react-three/drei/core/useSpriteLoader.js
var getFirstFrame = (frames, frameName) => {
	if (Array.isArray(frames)) return frames[0];
	else return frames[frameName !== null && frameName !== void 0 ? frameName : Object.keys(frames)[0]][0];
};
var checkIfFrameIsEmpty = (frameData) => {
	for (let i = 3; i < frameData.length; i += 4) if (frameData[i] !== 0) return false;
	return true;
};
function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, canvasRenderingContext2DSettings) {
	const viewportRef = import_react.useRef(useThree((state) => state.viewport));
	const spriteDataRef = import_react.useRef(null);
	const totalFrames = import_react.useRef(0);
	const aspectFactor = .1;
	const inputRef = import_react.useRef(input);
	const jsonRef = import_react.useRef(json);
	const animationFramesRef = import_react.useRef(animationNames);
	const [spriteData, setSpriteData] = (0, import_react.useState)(null);
	const [spriteTexture, setSpriteTexture] = import_react.useState(new Texture$1());
	const textureLoader = import_react.useMemo(() => new TextureLoader(), []);
	const [spriteObj, setSpriteObj] = (0, import_react.useState)(null);
	const calculateAspectRatio = import_react.useCallback((width, height, factor) => {
		const adaptedHeight = height * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height);
		const scaleX = width * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height) * factor;
		const scaleY = adaptedHeight * factor;
		const currentMaxScale = 1;
		let finalMaxScaleW = Math.min(currentMaxScale, scaleX);
		let finalMaxScaleH = Math.min(currentMaxScale, scaleY);
		if (scaleX > currentMaxScale) {
			finalMaxScaleW = currentMaxScale;
			finalMaxScaleH = scaleY / scaleX * currentMaxScale;
		}
		return new Vector3(finalMaxScaleW, finalMaxScaleH, 1);
	}, []);
	const getRowsAndColumns = import_react.useCallback((texture, totalFrames) => {
		if (texture.image) {
			const canvas = document.createElement("canvas");
			const ctx = canvas.getContext("2d", canvasRenderingContext2DSettings);
			if (!ctx) throw new Error("Failed to get 2d context");
			canvas.width = texture.image.width;
			canvas.height = texture.image.height;
			ctx.drawImage(texture.image, 0, 0);
			const width = texture.image.width;
			const height = texture.image.height;
			const cols = Math.round(Math.sqrt(totalFrames * (width / height)));
			const rows = Math.round(totalFrames / cols);
			const frameWidth = width / cols;
			const frameHeight = height / rows;
			const emptyFrames = [];
			for (let row = 0; row < rows; row++) for (let col = 0; col < cols; col++) {
				if (row * cols + col >= totalFrames) {
					emptyFrames.push({
						row,
						col
					});
					continue;
				}
				const frameData = ctx.getImageData(col * frameWidth, row * frameHeight, frameWidth, frameHeight).data;
				if (checkIfFrameIsEmpty(frameData)) emptyFrames.push({
					row,
					col
				});
			}
			return {
				rows,
				columns: cols,
				frameWidth,
				frameHeight,
				emptyFrames
			};
		} else return {
			rows: 0,
			columns: 0,
			frameWidth: 0,
			frameHeight: 0,
			emptyFrames: []
		};
	}, [canvasRenderingContext2DSettings]);
	const calculateScaleRatio = import_react.useCallback((frames) => {
		const processFrameArray = (frameArray) => {
			let largestFrame = null;
			for (const frame of frameArray) {
				const { w, h } = frame.frame;
				const area = w * h;
				if (!largestFrame || area > largestFrame.area) largestFrame = {
					w,
					h,
					area
				};
			}
			return frameArray.map((frame) => {
				const { w, h } = frame.frame;
				const area = w * h;
				const scaleRatio = largestFrame ? area === largestFrame.area ? 1 : Math.sqrt(area / largestFrame.area) : 1;
				return {
					...frame,
					scaleRatio
				};
			});
		};
		if (Array.isArray(frames)) return processFrameArray(frames);
		else {
			const result = {};
			for (const key in frames) result[key] = processFrameArray(frames[key]);
			return result;
		}
	}, []);
	const parseFrames = import_react.useCallback(() => {
		const sprites = {};
		const data = spriteDataRef.current;
		const delimiters = animationFramesRef.current;
		if (data) if (delimiters && Array.isArray(data["frames"])) {
			for (let i = 0; i < delimiters.length; i++) {
				sprites[delimiters[i]] = [];
				for (const value of data["frames"]) {
					const frameData = value["frame"];
					const sourceWidth = value["sourceSize"]["w"];
					const sourceHeight = value["sourceSize"]["h"];
					if (typeof value["filename"] === "string" && value["filename"].toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) sprites[delimiters[i]].push({
						...value,
						frame: frameData,
						sourceSize: {
							w: sourceWidth,
							h: sourceHeight
						}
					});
				}
			}
			for (const frame in sprites) {
				const scaleRatioData = calculateScaleRatio(sprites[frame]);
				if (Array.isArray(scaleRatioData)) sprites[frame] = scaleRatioData;
			}
			return sprites;
		} else if (delimiters && typeof data["frames"] === "object") {
			for (let i = 0; i < delimiters.length; i++) {
				sprites[delimiters[i]] = [];
				for (const innerKey in data["frames"]) {
					const value = data["frames"][innerKey];
					const frameData = value["frame"];
					const sourceWidth = value["sourceSize"]["w"];
					const sourceHeight = value["sourceSize"]["h"];
					if (typeof innerKey === "string" && innerKey.toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) sprites[delimiters[i]].push({
						...value,
						frame: frameData,
						sourceSize: {
							w: sourceWidth,
							h: sourceHeight
						}
					});
				}
			}
			for (const frame in sprites) {
				const scaleRatioData = calculateScaleRatio(sprites[frame]);
				if (Array.isArray(scaleRatioData)) sprites[frame] = scaleRatioData;
			}
			return sprites;
		} else {
			let spritesArr = [];
			if (data != null && data.frames) if (Array.isArray(data.frames)) spritesArr = data.frames.map((frame) => ({
				...frame,
				x: frame.frame.x,
				y: frame.frame.y,
				w: frame.frame.w,
				h: frame.frame.h
			}));
			else spritesArr = Object.values(data.frames).flat().map((frame) => ({
				...frame,
				x: frame.frame.x,
				y: frame.frame.y,
				w: frame.frame.w,
				h: frame.frame.h
			}));
			return calculateScaleRatio(spritesArr);
		}
		return [];
	}, [calculateScaleRatio, spriteDataRef]);
	const parseSpriteData = import_react.useCallback((json, _spriteTexture) => {
		let aspect = new Vector3(1, 1, 1);
		if (json === null) {
			if (_spriteTexture && numberOfFrames) {
				const width = _spriteTexture.image.width;
				const height = _spriteTexture.image.height;
				totalFrames.current = numberOfFrames;
				const { rows, columns, frameWidth, frameHeight, emptyFrames } = getRowsAndColumns(_spriteTexture, numberOfFrames);
				const nonJsonFrames = {
					frames: [],
					meta: {
						version: "1.0",
						size: {
							w: width,
							h: height
						},
						rows,
						columns,
						frameWidth,
						frameHeight,
						scale: "1"
					}
				};
				for (let row = 0; row < rows; row++) for (let col = 0; col < columns; col++) {
					if ((emptyFrames !== null && emptyFrames !== void 0 ? emptyFrames : []).some((coord) => coord.row === row && coord.col === col)) continue;
					if (Array.isArray(nonJsonFrames.frames)) nonJsonFrames.frames.push({
						frame: {
							x: col * frameWidth,
							y: row * frameHeight,
							w: frameWidth,
							h: frameHeight
						},
						scaleRatio: 1,
						rotated: false,
						trimmed: false,
						spriteSourceSize: {
							x: 0,
							y: 0,
							w: frameWidth,
							h: frameHeight
						},
						sourceSize: {
							w: frameWidth,
							h: frameHeight
						}
					});
				}
				aspect = calculateAspectRatio(frameWidth, frameHeight, aspectFactor);
				spriteDataRef.current = nonJsonFrames;
			}
			if (spriteDataRef.current && spriteDataRef.current.frames) spriteDataRef.current.frames = calculateScaleRatio(spriteDataRef.current.frames);
		} else if (_spriteTexture) {
			spriteDataRef.current = json;
			spriteDataRef.current.frames = parseFrames();
			totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
			const { w, h } = getFirstFrame(json.frames).sourceSize;
			aspect = calculateAspectRatio(w, h, aspectFactor);
		}
		setSpriteData(spriteDataRef.current);
		if ("encoding" in _spriteTexture) _spriteTexture.encoding = 3001;
		else if ("colorSpace" in _spriteTexture) _spriteTexture.colorSpace = SRGBColorSpace$2;
		setSpriteTexture(_spriteTexture);
		setSpriteObj({
			spriteTexture: _spriteTexture,
			spriteData: spriteDataRef.current,
			aspect
		});
	}, [
		getRowsAndColumns,
		numberOfFrames,
		parseFrames,
		calculateAspectRatio,
		calculateScaleRatio
	]);
	/**
	*
	*/
	const loadJsonAndTextureAndExecuteCallback = import_react.useCallback((jsonUrl, textureUrl, callback) => {
		const jsonPromise = fetch(jsonUrl).then((response) => response.json());
		const texturePromise = new Promise((resolve) => {
			textureLoader.load(textureUrl, resolve);
		});
		Promise.all([jsonPromise, texturePromise]).then((response) => {
			callback(response[0], response[1]);
		});
	}, [textureLoader]);
	const loadStandaloneSprite = import_react.useCallback((textureUrl) => {
		if (!textureUrl && !inputRef.current) throw new Error("Either textureUrl or input must be provided");
		const validUrl = textureUrl !== null && textureUrl !== void 0 ? textureUrl : inputRef.current;
		if (!validUrl) throw new Error("A valid texture URL must be provided");
		textureLoader.load(validUrl, (texture) => parseSpriteData(null, texture));
	}, [textureLoader, parseSpriteData]);
	const loadJsonAndTexture = import_react.useCallback((textureUrl, jsonUrl) => {
		if (jsonUrl && textureUrl) loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, parseSpriteData);
		else loadStandaloneSprite(textureUrl);
	}, [
		loadJsonAndTextureAndExecuteCallback,
		loadStandaloneSprite,
		parseSpriteData
	]);
	import_react.useLayoutEffect(() => {
		if (jsonRef.current && inputRef.current) loadJsonAndTextureAndExecuteCallback(jsonRef.current, inputRef.current, parseSpriteData);
		else if (inputRef.current) loadStandaloneSprite();
		const _inputRef = inputRef.current;
		return () => {
			if (_inputRef) useLoader.clear(TextureLoader, _inputRef);
		};
	}, [
		loadJsonAndTextureAndExecuteCallback,
		loadStandaloneSprite,
		parseSpriteData
	]);
	import_react.useLayoutEffect(() => {
		onLoad?.(spriteTexture, spriteData !== null && spriteData !== void 0 ? spriteData : null);
	}, [
		spriteTexture,
		spriteData,
		onLoad
	]);
	return {
		spriteObj,
		loadJsonAndTexture
	};
}
useSpriteLoader.preload = (url) => useLoader.preload(TextureLoader, url);
useSpriteLoader.clear = (input) => useLoader.clear(TextureLoader, input);
//#endregion
//#region node_modules/@react-three/drei/core/Helper.js
function useHelper(object3D, helperConstructor, ...args) {
	const helper = import_react.useRef(null);
	const scene = useThree((state) => state.scene);
	import_react.useLayoutEffect(() => {
		let currentHelper = void 0;
		if (object3D && object3D != null && object3D.current && helperConstructor) helper.current = currentHelper = new helperConstructor(object3D.current, ...args);
		if (currentHelper) {
			currentHelper.traverse((child) => child.raycast = () => null);
			scene.add(currentHelper);
			return () => {
				helper.current = void 0;
				scene.remove(currentHelper);
				currentHelper.dispose == null || currentHelper.dispose();
			};
		}
	}, [
		scene,
		helperConstructor,
		object3D,
		...args
	]);
	useFrame(() => {
		var _helper$current;
		(_helper$current = helper.current) == null || _helper$current.update == null || _helper$current.update();
	});
	return helper;
}
var Helper = ({ type: helperConstructor, args = [] }) => {
	const thisRef = import_react.useRef(null);
	const parentRef = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		parentRef.current = thisRef.current.parent;
	});
	useHelper(parentRef, helperConstructor, ...args);
	return /*#__PURE__*/ import_react.createElement("object3D", { ref: thisRef });
};
//#endregion
//#region node_modules/@react-three/drei/helpers/useEffectfulState.js
var import_stats_min = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
	(function(f, e) {
		"object" === typeof exports && "undefined" !== typeof module ? module.exports = e() : "function" === typeof define && define.amd ? define(e) : f.Stats = e();
	})(exports, function() {
		var f = function() {
			function e(a) {
				c.appendChild(a.dom);
				return a;
			}
			function u(a) {
				for (var d = 0; d < c.children.length; d++) c.children[d].style.display = d === a ? "block" : "none";
				l = a;
			}
			var l = 0, c = document.createElement("div");
			c.style.cssText = "position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
			c.addEventListener("click", function(a) {
				a.preventDefault();
				u(++l % c.children.length);
			}, !1);
			var k = (performance || Date).now(), g = k, a = 0, r = e(new f.Panel("FPS", "#0ff", "#002")), h = e(new f.Panel("MS", "#0f0", "#020"));
			if (self.performance && self.performance.memory) var t = e(new f.Panel("MB", "#f08", "#201"));
			u(0);
			return {
				REVISION: 16,
				dom: c,
				addPanel: e,
				showPanel: u,
				begin: function() {
					k = (performance || Date).now();
				},
				end: function() {
					a++;
					var c = (performance || Date).now();
					h.update(c - k, 200);
					if (c > g + 1e3 && (r.update(1e3 * a / (c - g), 100), g = c, a = 0, t)) {
						var d = performance.memory;
						t.update(d.usedJSHeapSize / 1048576, d.jsHeapSizeLimit / 1048576);
					}
					return c;
				},
				update: function() {
					k = this.end();
				},
				domElement: c,
				setMode: u
			};
		};
		f.Panel = function(e, f, l) {
			var c = Infinity, k = 0, g = Math.round, a = g(window.devicePixelRatio || 1), r = 80 * a, h = 48 * a, t = 3 * a, v = 2 * a, d = 3 * a, m = 15 * a, n = 74 * a, p = 30 * a, q = document.createElement("canvas");
			q.width = r;
			q.height = h;
			q.style.cssText = "width:80px;height:48px";
			var b = q.getContext("2d");
			b.font = "bold " + 9 * a + "px Helvetica,Arial,sans-serif";
			b.textBaseline = "top";
			b.fillStyle = l;
			b.fillRect(0, 0, r, h);
			b.fillStyle = f;
			b.fillText(e, t, v);
			b.fillRect(d, m, n, p);
			b.fillStyle = l;
			b.globalAlpha = .9;
			b.fillRect(d, m, n, p);
			return {
				dom: q,
				update: function(h, w) {
					c = Math.min(c, h);
					k = Math.max(k, h);
					b.fillStyle = l;
					b.globalAlpha = 1;
					b.fillRect(0, 0, r, m);
					b.fillStyle = f;
					b.fillText(g(h) + " " + e + " (" + g(c) + "-" + g(k) + ")", t, v);
					b.drawImage(q, d + a, m, n - a, p, d, m, n - a, p);
					b.fillRect(d + n - a, m, a, p);
					b.fillStyle = l;
					b.globalAlpha = .9;
					b.fillRect(d + n - a, m, a, g((1 - h / w) * p));
				}
			};
		};
		return f;
	});
})))());
function call(ref, value) {
	if (typeof ref === "function") ref(value);
	else if (ref != null) ref.current = value;
}
function useEffectfulState(fn, deps = [], cb) {
	const [state, set] = import_react.useState();
	import_react.useLayoutEffect(() => {
		const value = fn();
		set(value);
		call(cb, value);
		return () => call(cb, null);
	}, deps);
	return state;
}
//#endregion
//#region node_modules/@react-three/drei/core/Stats.js
function Stats({ showPanel = 0, className, parent }) {
	const stats = useEffectfulState(() => new import_stats_min.default(), []);
	import_react.useEffect(() => {
		if (stats) {
			const node = parent && parent.current || document.body;
			stats.showPanel(showPanel);
			node?.appendChild(stats.dom);
			const classNames = (className !== null && className !== void 0 ? className : "").split(" ").filter((cls) => cls);
			if (classNames.length) stats.dom.classList.add(...classNames);
			const begin = addEffect(() => stats.begin());
			const end = addAfterEffect(() => stats.end());
			return () => {
				if (classNames.length) stats.dom.classList.remove(...classNames);
				node?.removeChild(stats.dom);
				begin();
				end();
			};
		}
	}, [
		parent,
		stats,
		className,
		showPanel
	]);
	return null;
}
//#endregion
//#region node_modules/stats-gl/dist/panel.js
var Panel = class {
	constructor(name, fg, bg) {
		this.name = name;
		this.fg = fg;
		this.bg = bg;
		this.gradient = null;
		this.PR = Math.round(window.devicePixelRatio || 1);
		this.WIDTH = 90 * this.PR;
		this.HEIGHT = 48 * this.PR;
		this.TEXT_X = 3 * this.PR;
		this.TEXT_Y = 2 * this.PR;
		this.GRAPH_X = 3 * this.PR;
		this.GRAPH_Y = 15 * this.PR;
		this.GRAPH_WIDTH = 84 * this.PR;
		this.GRAPH_HEIGHT = 30 * this.PR;
		this.canvas = document.createElement("canvas");
		this.canvas.width = this.WIDTH;
		this.canvas.height = this.HEIGHT;
		this.canvas.style.width = "90px";
		this.canvas.style.height = "48px";
		this.canvas.style.position = "absolute";
		this.canvas.style.cssText = "width:90px;height:48px";
		this.context = this.canvas.getContext("2d");
		this.initializeCanvas();
	}
	createGradient() {
		if (!this.context) throw new Error("No context");
		const gradient = this.context.createLinearGradient(0, this.GRAPH_Y, 0, this.GRAPH_Y + this.GRAPH_HEIGHT);
		let startColor;
		const endColor = this.fg;
		switch (this.fg.toLowerCase()) {
			case "#0ff":
				startColor = "#006666";
				break;
			case "#0f0":
				startColor = "#006600";
				break;
			case "#ff0":
				startColor = "#666600";
				break;
			case "#e1e1e1":
				startColor = "#666666";
				break;
			default:
				startColor = this.bg;
				break;
		}
		gradient.addColorStop(0, startColor);
		gradient.addColorStop(1, endColor);
		return gradient;
	}
	initializeCanvas() {
		if (!this.context) return;
		this.context.font = "bold " + 9 * this.PR + "px Helvetica,Arial,sans-serif";
		this.context.textBaseline = "top";
		this.gradient = this.createGradient();
		this.context.fillStyle = this.bg;
		this.context.fillRect(0, 0, this.WIDTH, this.HEIGHT);
		this.context.fillStyle = this.fg;
		this.context.fillText(this.name, this.TEXT_X, this.TEXT_Y);
		this.context.fillStyle = this.fg;
		this.context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT);
		this.context.fillStyle = this.bg;
		this.context.globalAlpha = .9;
		this.context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT);
	}
	update(value, valueGraph, maxValue, maxGraph, decimals = 0) {
		if (!this.context || !this.gradient) return;
		const min = Math.min(Infinity, value);
		const max = Math.max(maxValue, value);
		maxGraph = Math.max(maxGraph, valueGraph);
		this.context.globalAlpha = 1;
		this.context.fillStyle = this.bg;
		this.context.fillRect(0, 0, this.WIDTH, this.GRAPH_Y);
		this.context.fillStyle = this.fg;
		this.context.fillText(`${value.toFixed(decimals)} ${this.name} (${min.toFixed(decimals)}-${parseFloat(max.toFixed(decimals))})`, this.TEXT_X, this.TEXT_Y);
		this.context.drawImage(this.canvas, this.GRAPH_X + this.PR, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT, this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT);
		const columnHeight = this.GRAPH_HEIGHT - (1 - valueGraph / maxGraph) * this.GRAPH_HEIGHT;
		if (columnHeight > 0) {
			this.context.globalAlpha = 1;
			this.context.fillStyle = this.gradient;
			this.context.fillRect(this.GRAPH_X + this.GRAPH_WIDTH - this.PR, this.GRAPH_Y + this.GRAPH_HEIGHT - columnHeight, this.PR, columnHeight);
		}
	}
};
//#endregion
//#region node_modules/stats-gl/dist/main.js
var _Stats = class _Stats2 {
	constructor({ trackGPU = false, logsPerSecond = 30, samplesLog = 60, samplesGraph = 10, precision = 2, minimal = false, horizontal = true, mode = 0 } = {}) {
		this.gl = null;
		this.ext = null;
		this.activeQuery = null;
		this.gpuQueries = [];
		this.threeRendererPatched = false;
		this.frames = 0;
		this.renderCount = 0;
		this.isRunningCPUProfiling = false;
		this.totalCpuDuration = 0;
		this.totalGpuDuration = 0;
		this.totalGpuDurationCompute = 0;
		this.totalFps = 0;
		this.gpuPanel = null;
		this.gpuPanelCompute = null;
		this.averageFps = {
			logs: [],
			graph: []
		};
		this.averageCpu = {
			logs: [],
			graph: []
		};
		this.averageGpu = {
			logs: [],
			graph: []
		};
		this.averageGpuCompute = {
			logs: [],
			graph: []
		};
		this.handleClick = (event) => {
			event.preventDefault();
			this.showPanel(++this.mode % this.dom.children.length);
		};
		this.handleResize = () => {
			this.resizePanel(this.fpsPanel, 0);
			this.resizePanel(this.msPanel, 1);
			if (this.gpuPanel) this.resizePanel(this.gpuPanel, 2);
			if (this.gpuPanelCompute) this.resizePanel(this.gpuPanelCompute, 3);
		};
		this.mode = mode;
		this.horizontal = horizontal;
		this.minimal = minimal;
		this.trackGPU = trackGPU;
		this.samplesLog = samplesLog;
		this.samplesGraph = samplesGraph;
		this.precision = precision;
		this.logsPerSecond = logsPerSecond;
		this.dom = document.createElement("div");
		this.initializeDOM();
		this.beginTime = performance.now();
		this.prevTime = this.beginTime;
		this.prevCpuTime = this.beginTime;
		this.fpsPanel = this.addPanel(new _Stats2.Panel("FPS", "#0ff", "#002"), 0);
		this.msPanel = this.addPanel(new _Stats2.Panel("CPU", "#0f0", "#020"), 1);
		this.setupEventListeners();
	}
	initializeDOM() {
		this.dom.style.cssText = `
      position: fixed;
      top: 0;
      left: 0;
      opacity: 0.9;
      z-index: 10000;
      ${this.minimal ? "cursor: pointer;" : ""}
    `;
	}
	setupEventListeners() {
		if (this.minimal) {
			this.dom.addEventListener("click", this.handleClick);
			this.showPanel(this.mode);
		} else window.addEventListener("resize", this.handleResize);
	}
	async init(canvasOrGL) {
		if (!canvasOrGL) {
			console.error("Stats: The \"canvas\" parameter is undefined.");
			return;
		}
		if (this.handleThreeRenderer(canvasOrGL)) return;
		if (await this.handleWebGPURenderer(canvasOrGL)) return;
		if (!this.initializeWebGL(canvasOrGL)) return;
	}
	handleThreeRenderer(renderer) {
		if (renderer.isWebGLRenderer && !this.threeRendererPatched) {
			this.patchThreeRenderer(renderer);
			this.gl = renderer.getContext();
			if (this.trackGPU) this.initializeGPUTracking();
			return true;
		}
		return false;
	}
	async handleWebGPURenderer(renderer) {
		if (renderer.isWebGPURenderer) {
			if (this.trackGPU) {
				renderer.backend.trackTimestamp = true;
				if (await renderer.hasFeatureAsync("timestamp-query")) this.initializeWebGPUPanels();
			}
			this.info = renderer.info;
			return true;
		}
		return false;
	}
	initializeWebGPUPanels() {
		this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"), 2);
		this.gpuPanelCompute = this.addPanel(new _Stats2.Panel("CPT", "#e1e1e1", "#212121"), 3);
	}
	initializeWebGL(canvasOrGL) {
		if (canvasOrGL instanceof WebGL2RenderingContext) this.gl = canvasOrGL;
		else if (canvasOrGL instanceof HTMLCanvasElement || canvasOrGL instanceof OffscreenCanvas) {
			this.gl = canvasOrGL.getContext("webgl2");
			if (!this.gl) {
				console.error("Stats: Unable to obtain WebGL2 context.");
				return false;
			}
		} else {
			console.error("Stats: Invalid input type. Expected WebGL2RenderingContext, HTMLCanvasElement, or OffscreenCanvas.");
			return false;
		}
		return true;
	}
	initializeGPUTracking() {
		if (this.gl) {
			this.ext = this.gl.getExtension("EXT_disjoint_timer_query_webgl2");
			if (this.ext) this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"), 2);
		}
	}
	begin() {
		if (!this.isRunningCPUProfiling) this.beginProfiling("cpu-started");
		if (!this.gl || !this.ext) return;
		if (this.activeQuery) this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
		this.activeQuery = this.gl.createQuery();
		if (this.activeQuery) this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, this.activeQuery);
	}
	end() {
		this.renderCount++;
		if (this.gl && this.ext && this.activeQuery) {
			this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
			this.gpuQueries.push({ query: this.activeQuery });
			this.activeQuery = null;
		}
	}
	update() {
		if (!this.info) this.processGpuQueries();
		else this.processWebGPUTimestamps();
		this.endProfiling("cpu-started", "cpu-finished", "cpu-duration");
		this.updateAverages();
		this.resetCounters();
	}
	processWebGPUTimestamps() {
		this.totalGpuDuration = this.info.render.timestamp;
		this.totalGpuDurationCompute = this.info.compute.timestamp;
		this.addToAverage(this.totalGpuDurationCompute, this.averageGpuCompute);
	}
	updateAverages() {
		this.addToAverage(this.totalCpuDuration, this.averageCpu);
		this.addToAverage(this.totalGpuDuration, this.averageGpu);
	}
	resetCounters() {
		this.renderCount = 0;
		if (this.totalCpuDuration === 0) this.beginProfiling("cpu-started");
		this.totalCpuDuration = 0;
		this.totalFps = 0;
		this.beginTime = this.endInternal();
	}
	resizePanel(panel, offset) {
		panel.canvas.style.position = "absolute";
		if (this.minimal) panel.canvas.style.display = "none";
		else {
			panel.canvas.style.display = "block";
			if (this.horizontal) {
				panel.canvas.style.top = "0px";
				panel.canvas.style.left = offset * panel.WIDTH / panel.PR + "px";
			} else {
				panel.canvas.style.left = "0px";
				panel.canvas.style.top = offset * panel.HEIGHT / panel.PR + "px";
			}
		}
	}
	addPanel(panel, offset) {
		if (panel.canvas) {
			this.dom.appendChild(panel.canvas);
			this.resizePanel(panel, offset);
		}
		return panel;
	}
	showPanel(id) {
		for (let i = 0; i < this.dom.children.length; i++) {
			const child = this.dom.children[i];
			child.style.display = i === id ? "block" : "none";
		}
		this.mode = id;
	}
	processGpuQueries() {
		if (!this.gl || !this.ext) return;
		this.totalGpuDuration = 0;
		this.gpuQueries.forEach((queryInfo, index) => {
			if (this.gl) {
				const available = this.gl.getQueryParameter(queryInfo.query, this.gl.QUERY_RESULT_AVAILABLE);
				const disjoint = this.gl.getParameter(this.ext.GPU_DISJOINT_EXT);
				if (available && !disjoint) {
					const duration = this.gl.getQueryParameter(queryInfo.query, this.gl.QUERY_RESULT) * 1e-6;
					this.totalGpuDuration += duration;
					this.gl.deleteQuery(queryInfo.query);
					this.gpuQueries.splice(index, 1);
				}
			}
		});
	}
	endInternal() {
		this.frames++;
		const time = (performance || Date).now();
		const elapsed = time - this.prevTime;
		if (time >= this.prevCpuTime + 1e3 / this.logsPerSecond) {
			const fps = Math.round(this.frames * 1e3 / elapsed);
			this.addToAverage(fps, this.averageFps);
			this.updatePanel(this.fpsPanel, this.averageFps, 0);
			this.updatePanel(this.msPanel, this.averageCpu, this.precision);
			this.updatePanel(this.gpuPanel, this.averageGpu, this.precision);
			if (this.gpuPanelCompute) this.updatePanel(this.gpuPanelCompute, this.averageGpuCompute);
			this.frames = 0;
			this.prevCpuTime = time;
			this.prevTime = time;
		}
		return time;
	}
	addToAverage(value, averageArray) {
		averageArray.logs.push(value);
		if (averageArray.logs.length > this.samplesLog) averageArray.logs.shift();
		averageArray.graph.push(value);
		if (averageArray.graph.length > this.samplesGraph) averageArray.graph.shift();
	}
	beginProfiling(marker) {
		if (window.performance) {
			window.performance.mark(marker);
			this.isRunningCPUProfiling = true;
		}
	}
	endProfiling(startMarker, endMarker, measureName) {
		if (window.performance && endMarker && this.isRunningCPUProfiling) {
			window.performance.mark(endMarker);
			const cpuMeasure = performance.measure(measureName, startMarker, endMarker);
			this.totalCpuDuration += cpuMeasure.duration;
			this.isRunningCPUProfiling = false;
		}
	}
	updatePanel(panel, averageArray, precision = 2) {
		if (averageArray.logs.length > 0) {
			let sumLog = 0;
			let max = .01;
			for (let i = 0; i < averageArray.logs.length; i++) {
				sumLog += averageArray.logs[i];
				if (averageArray.logs[i] > max) max = averageArray.logs[i];
			}
			let sumGraph = 0;
			let maxGraph = .01;
			for (let i = 0; i < averageArray.graph.length; i++) {
				sumGraph += averageArray.graph[i];
				if (averageArray.graph[i] > maxGraph) maxGraph = averageArray.graph[i];
			}
			if (panel) panel.update(sumLog / Math.min(averageArray.logs.length, this.samplesLog), sumGraph / Math.min(averageArray.graph.length, this.samplesGraph), max, maxGraph, precision);
		}
	}
	get domElement() {
		return this.dom;
	}
	patchThreeRenderer(renderer) {
		const originalRenderMethod = renderer.render;
		const statsInstance = this;
		renderer.render = function(scene, camera) {
			statsInstance.begin();
			originalRenderMethod.call(this, scene, camera);
			statsInstance.end();
		};
		this.threeRendererPatched = true;
	}
};
_Stats.Panel = Panel;
var Stats$1 = _Stats;
//#endregion
//#region node_modules/@react-three/drei/core/StatsGl.js
var StatsGl = /* @__PURE__ */ import_react.forwardRef(function StatsGl({ className, parent, id, clearStatsGlStyle, ...props }, fref) {
	const gl = useThree((state) => state.gl);
	const stats = import_react.useMemo(() => {
		const stats = new Stats$1({ ...props });
		stats.init(gl);
		return stats;
	}, [gl]);
	import_react.useImperativeHandle(fref, () => stats.domElement, [stats]);
	import_react.useEffect(() => {
		if (stats) {
			const node = parent && parent.current || document.body;
			node?.appendChild(stats.domElement);
			stats.domElement.querySelectorAll("canvas").forEach((canvas) => {
				canvas.style.removeProperty("position");
			});
			if (id) stats.domElement.id = id;
			if (clearStatsGlStyle) stats.domElement.removeAttribute("style");
			stats.domElement.removeAttribute("style");
			const classNames = (className !== null && className !== void 0 ? className : "").split(" ").filter((cls) => cls);
			if (classNames.length) stats.domElement.classList.add(...classNames);
			const end = addAfterEffect(() => stats.update());
			return () => {
				if (classNames.length) stats.domElement.classList.remove(...classNames);
				node?.removeChild(stats.domElement);
				end();
			};
		}
	}, [
		parent,
		stats,
		className,
		id,
		clearStatsGlStyle
	]);
	return null;
});
//#endregion
//#region node_modules/@react-three/drei/core/useDepthBuffer.js
function useDepthBuffer({ size = 256, frames = Infinity } = {}) {
	const dpr = useThree((state) => state.viewport.dpr);
	const { width, height } = useThree((state) => state.size);
	const w = size || width * dpr;
	const h = size || height * dpr;
	const depthConfig = import_react.useMemo(() => {
		const depthTexture = new DepthTexture(w, h);
		depthTexture.format = DepthFormat;
		depthTexture.type = UnsignedShortType;
		return { depthTexture };
	}, [w, h]);
	let count = 0;
	const depthFBO = useFBO(w, h, depthConfig);
	useFrame((state) => {
		if (frames === Infinity || count < frames) {
			state.gl.setRenderTarget(depthFBO);
			state.gl.render(state.scene, state.camera);
			state.gl.setRenderTarget(null);
			count++;
		}
	});
	return depthFBO.depthTexture;
}
//#endregion
//#region node_modules/@react-three/drei/core/useAspect.js
function useAspect(width, height, factor = 1) {
	const v = useThree((state) => state.viewport);
	const adaptedHeight = height * (v.aspect > width / height ? v.width / width : v.height / height);
	return [
		width * (v.aspect > width / height ? v.width / width : v.height / height) * factor,
		adaptedHeight * factor,
		1
	];
}
//#endregion
//#region node_modules/@react-three/drei/core/useCamera.js
function useCamera(camera, props) {
	const pointer = useThree((state) => state.pointer);
	const [raycast] = import_react.useState(() => {
		const raycaster = new Raycaster();
		if (props) applyProps(raycaster, props);
		return function(_, intersects) {
			raycaster.setFromCamera(pointer, camera instanceof Camera ? camera : camera.current);
			const rc = this.constructor.prototype.raycast.bind(this);
			if (rc) rc(raycaster, intersects);
		};
	});
	return raycast;
}
//#endregion
//#region node_modules/detect-gpu/dist/detect-gpu.esm.js
function e(e, t, r, n) {
	return new (r || (r = Promise))((function(o, a) {
		function i(e) {
			try {
				d(n.next(e));
			} catch (e) {
				a(e);
			}
		}
		function c(e) {
			try {
				d(n.throw(e));
			} catch (e) {
				a(e);
			}
		}
		function d(e) {
			var t;
			e.done ? o(e.value) : (t = e.value, t instanceof r ? t : new r((function(e) {
				e(t);
			}))).then(i, c);
		}
		d((n = n.apply(e, t || [])).next());
	}));
}
var t = [
	"geforce 320m",
	"geforce 8600",
	"geforce 8600m gt",
	"geforce 8800 gs",
	"geforce 8800 gt",
	"geforce 9400",
	"geforce 9400m g",
	"geforce 9400m",
	"geforce 9600m gt",
	"geforce 9600m",
	"geforce fx go5200",
	"geforce gt 120",
	"geforce gt 130",
	"geforce gt 330m",
	"geforce gtx 285",
	"google swiftshader",
	"intel g41",
	"intel g45",
	"intel gma 4500mhd",
	"intel gma x3100",
	"intel hd 3000",
	"intel q45",
	"legacy",
	"mali-2",
	"mali-3",
	"mali-4",
	"quadro fx 1500",
	"quadro fx 4",
	"quadro fx 5",
	"radeon hd 2400",
	"radeon hd 2600",
	"radeon hd 4670",
	"radeon hd 4850",
	"radeon hd 4870",
	"radeon hd 5670",
	"radeon hd 5750",
	"radeon hd 6290",
	"radeon hd 6300",
	"radeon hd 6310",
	"radeon hd 6320",
	"radeon hd 6490m",
	"radeon hd 6630m",
	"radeon hd 6750m",
	"radeon hd 6770m",
	"radeon hd 6970m",
	"sgx 543",
	"sgx543"
];
function r(e) {
	return e = e.toLowerCase().replace(/.*angle ?\((.+)\)(?: on vulkan [0-9.]+)?$/i, "$1").replace(/\s(\d{1,2}gb|direct3d.+$)|\(r\)| \([^)]+\)$/g, "").replace(/(?:vulkan|opengl) \d+\.\d+(?:\.\d+)?(?: \((.*)\))?/, "$1");
}
var n = "undefined" == typeof window, o = (() => {
	if (n) return;
	const { userAgent: e, platform: t, maxTouchPoints: r } = window.navigator, o = /(iphone|ipod|ipad)/i.test(e), a = "iPad" === t || "MacIntel" === t && r > 0 && !window.MSStream;
	return {
		isIpad: a,
		isMobile: /android/i.test(e) || o || a,
		isSafari12: /Version\/12.+Safari/.test(e),
		isFirefox: /Firefox/.test(e)
	};
})();
function a(e, t, r) {
	if (!r) return [t];
	const n = function(e) {
		const t = "\n    precision highp float;\n    attribute vec3 aPosition;\n    varying float vvv;\n    void main() {\n      vvv = 0.31622776601683794;\n      gl_Position = vec4(aPosition, 1.0);\n    }\n  ", r = "\n    precision highp float;\n    varying float vvv;\n    void main() {\n      vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * vvv;\n      enc = fract(enc);\n      enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n      gl_FragColor = enc;\n    }\n  ", n = e.createShader(35633), o = e.createShader(35632), a = e.createProgram();
		if (!(o && n && a)) return;
		e.shaderSource(n, t), e.shaderSource(o, r), e.compileShader(n), e.compileShader(o), e.attachShader(a, n), e.attachShader(a, o), e.linkProgram(a), e.detachShader(a, n), e.detachShader(a, o), e.deleteShader(n), e.deleteShader(o), e.useProgram(a);
		const i = e.createBuffer();
		e.bindBuffer(34962, i), e.bufferData(34962, new Float32Array([
			-1,
			-1,
			0,
			3,
			-1,
			0,
			-1,
			3,
			0
		]), 35044);
		const c = e.getAttribLocation(a, "aPosition");
		e.vertexAttribPointer(c, 3, 5126, !1, 0, 0), e.enableVertexAttribArray(c), e.clearColor(1, 1, 1, 1), e.clear(16384), e.viewport(0, 0, 1, 1), e.drawArrays(4, 0, 3);
		const d = new Uint8Array(4);
		return e.readPixels(0, 0, 1, 1, 6408, 5121, d), e.deleteProgram(a), e.deleteBuffer(i), d.join("");
	}(e), a = "801621810", i = "8016218135", c = "80162181161", d = (null == o ? void 0 : o.isIpad) ? [
		[
			"a7",
			c,
			12
		],
		[
			"a8",
			i,
			15
		],
		[
			"a8x",
			i,
			15
		],
		[
			"a9",
			i,
			15
		],
		[
			"a9x",
			i,
			15
		],
		[
			"a10",
			i,
			15
		],
		[
			"a10x",
			i,
			15
		],
		[
			"a12",
			a,
			15
		],
		[
			"a12x",
			a,
			15
		],
		[
			"a12z",
			a,
			15
		],
		[
			"a14",
			a,
			15
		],
		[
			"a15",
			a,
			15
		],
		[
			"m1",
			a,
			15
		],
		[
			"m2",
			a,
			15
		]
	] : [
		[
			"a7",
			c,
			12
		],
		[
			"a8",
			i,
			12
		],
		[
			"a9",
			i,
			15
		],
		[
			"a10",
			i,
			15
		],
		[
			"a11",
			a,
			15
		],
		[
			"a12",
			a,
			15
		],
		[
			"a13",
			a,
			15
		],
		[
			"a14",
			a,
			15
		],
		[
			"a15",
			a,
			15
		],
		[
			"a16",
			a,
			15
		],
		[
			"a17",
			a,
			15
		]
	];
	let l;
	"80162181255" === n ? l = d.filter((([, , e]) => e >= 14)) : (l = d.filter((([, e]) => e === n)), l.length || (l = d));
	return l.map((([e]) => `apple ${e} gpu`));
}
var i$1 = class extends Error {
	constructor(e) {
		super(e), Object.setPrototypeOf(this, new.target.prototype);
	}
};
var c = [], d = [];
function l(e, t) {
	if (e === t) return 0;
	const r = e;
	e.length > t.length && (e = t, t = r);
	let n = e.length, o = t.length;
	for (; n > 0 && e.charCodeAt(~-n) === t.charCodeAt(~-o);) n--, o--;
	let a, i = 0;
	for (; i < n && e.charCodeAt(i) === t.charCodeAt(i);) i++;
	if (n -= i, o -= i, 0 === n) return o;
	let l, s, f = 0, u = 0, g = 0;
	for (; u < n;) d[u] = e.charCodeAt(i + u), c[u] = ++u;
	for (; g < o;) for (a = t.charCodeAt(i + g), l = g++, f = g, u = 0; u < n; u++) s = a === d[u] ? l : l + 1, l = c[u], f = c[u] = l > f ? s > f ? f + 1 : s : s > l ? l + 1 : s;
	return f;
}
function s(e) {
	return null != e;
}
var f = ({ mobileTiers: c = [
	0,
	15,
	30,
	60
], desktopTiers: d = [
	0,
	15,
	30,
	60
], override: f = {}, glContext: u, failIfMajorPerformanceCaveat: g = !1, benchmarksURL: h = "https://unpkg.com/detect-gpu@5.0.70/dist/benchmarks" } = {}) => e(void 0, void 0, void 0, (function* () {
	const p = {};
	if (n) return {
		tier: 0,
		type: "SSR"
	};
	const { isIpad: m = !!(null == o ? void 0 : o.isIpad), isMobile: v = !!(null == o ? void 0 : o.isMobile), screenSize: w = window.screen, loadBenchmarks: x = ((t) => e(void 0, void 0, void 0, (function* () {
		const e = yield fetch(`${h}/${t}`).then(((e) => e.json()));
		if (parseInt(e.shift().split(".")[0], 10) < 4) throw new i$1("Detect GPU benchmark data is out of date. Please update to version 4x");
		return e;
	}))) } = f;
	let { renderer: A } = f;
	const P = (e, t, r, n, o) => ({
		device: o,
		fps: n,
		gpu: r,
		isMobile: v,
		tier: e,
		type: t
	});
	let S, b = "";
	if (A) A = r(A), S = [A];
	else {
		const e = u || function(e, t = !1) {
			const r = {
				alpha: !1,
				antialias: !1,
				depth: !1,
				failIfMajorPerformanceCaveat: t,
				powerPreference: "high-performance",
				stencil: !1
			};
			e && delete r.powerPreference;
			const n = window.document.createElement("canvas"), o = n.getContext("webgl", r) || n.getContext("experimental-webgl", r);
			return null != o ? o : void 0;
		}(null == o ? void 0 : o.isSafari12, g);
		if (!e) return P(0, "WEBGL_UNSUPPORTED");
		const t = (null == o ? void 0 : o.isFirefox) ? null : e.getExtension("WEBGL_debug_renderer_info");
		if (A = t ? e.getParameter(t.UNMASKED_RENDERER_WEBGL) : e.getParameter(e.RENDERER), !A) return P(1, "FALLBACK");
		b = A, A = r(A), S = function(e, t, r) {
			return "apple gpu" === t ? a(e, t, r) : [t];
		}(e, A, v);
	}
	const E = (yield Promise.all(S.map((function(t) {
		var r;
		return e(this, void 0, void 0, (function* () {
			const e = ((e) => {
				const t = v ? [
					"adreno",
					"apple",
					"mali-t",
					"mali",
					"nvidia",
					"powervr",
					"samsung"
				] : [
					"intel",
					"apple",
					"amd",
					"radeon",
					"nvidia",
					"geforce",
					"adreno"
				];
				for (const r of t) if (e.includes(r)) return r;
			})(t);
			if (!e) return;
			const n = `${v ? "m" : "d"}-${e}${m ? "-ipad" : ""}.json`, o = p[n] = null !== (r = p[n]) && void 0 !== r ? r : x(n);
			let a;
			try {
				a = yield o;
			} catch (e) {
				if (e instanceof i$1) throw e;
				return;
			}
			const c = function(e) {
				var t;
				const r = (e = e.replace(/\([^)]+\)/, "")).match(/\d+/) || e.match(/(\W|^)([A-Za-z]{1,3})(\W|$)/g);
				return null !== (t = null == r ? void 0 : r.join("").replace(/\W|amd/g, "")) && void 0 !== t ? t : "";
			}(t);
			let d = a.filter((([, e]) => e === c));
			d.length || (d = a.filter((([e]) => e.includes(t))));
			const s = d.length;
			if (0 === s) return;
			const f = t.split(/[.,()\[\]/\s]/g).sort().filter(((e, t, r) => 0 === t || e !== r[t - 1])).join(" ");
			let u, [g, , , , h] = s > 1 ? d.map(((e) => [e, l(f, e[2])])).sort((([, e], [, t]) => e - t))[0][0] : d[0], A = Number.MAX_VALUE;
			const { devicePixelRatio: P } = window, S = w.width * P * w.height * P;
			for (const e of h) {
				const [t, r] = e, n = t * r, o = Math.abs(S - n);
				o < A && (A = o, u = e);
			}
			if (!u) return;
			const [, , b, E] = u;
			return [
				A,
				b,
				g,
				E
			];
		}));
	})))).filter(s).sort((([e = Number.MAX_VALUE, t], [r = Number.MAX_VALUE, n]) => e === r ? t - n : e - r));
	if (!E.length) {
		const e = t.find(((e) => A.includes(e)));
		return e ? P(0, "BLOCKLISTED", e) : P(1, "FALLBACK", `${A} (${b})`);
	}
	const [, y, C, L] = E[0];
	if (-1 === y) return P(0, "BLOCKLISTED", C, y, L);
	const M = v ? c : d;
	let $ = 0;
	for (let e = 0; e < M.length; e++) y >= M[e] && ($ = e);
	return P($, "BENCHMARK", C, y, L);
}));
//#endregion
//#region node_modules/@react-three/drei/core/DetectGPU.js
var useDetectGPU = (props) => suspend(() => f(props), ["useDetectGPU"]);
function DetectGPU({ children, ...options }) {
	const result = useDetectGPU(options);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(result));
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/Constants.js
var TRIANGLE_INTERSECT_COST = 1.25;
var IS_LEAFNODE_FLAG = 65535;
var FLOAT32_EPSILON = Math.pow(2, -24);
var SKIP_GENERATION = Symbol("SKIP_GENERATION");
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/geometryUtils.js
function getVertexCount(geo) {
	return geo.index ? geo.index.count : geo.attributes.position.count;
}
function getTriCount(geo) {
	return getVertexCount(geo) / 3;
}
function getIndexArray(vertexCount, BufferConstructor = ArrayBuffer) {
	if (vertexCount > 65535) return new Uint32Array(new BufferConstructor(4 * vertexCount));
	else return new Uint16Array(new BufferConstructor(2 * vertexCount));
}
function ensureIndex(geo, options) {
	if (!geo.index) {
		const vertexCount = geo.attributes.position.count;
		const index = getIndexArray(vertexCount, options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer);
		geo.setIndex(new BufferAttribute(index, 1));
		for (let i = 0; i < vertexCount; i++) index[i] = i;
	}
}
function getFullGeometryRange(geo, range) {
	const triCount = getTriCount(geo);
	const drawRange = range ? range : geo.drawRange;
	const start = drawRange.start / 3;
	const end = (drawRange.start + drawRange.count) / 3;
	const offset = Math.max(0, start);
	const count = Math.min(triCount, end) - offset;
	return [{
		offset: Math.floor(offset),
		count: Math.floor(count)
	}];
}
function getRootIndexRanges(geo, range) {
	if (!geo.groups || !geo.groups.length) return getFullGeometryRange(geo, range);
	const ranges = [];
	const rangeBoundaries = /* @__PURE__ */ new Set();
	const drawRange = range ? range : geo.drawRange;
	const drawRangeStart = drawRange.start / 3;
	const drawRangeEnd = (drawRange.start + drawRange.count) / 3;
	for (const group of geo.groups) {
		const groupStart = group.start / 3;
		const groupEnd = (group.start + group.count) / 3;
		rangeBoundaries.add(Math.max(drawRangeStart, groupStart));
		rangeBoundaries.add(Math.min(drawRangeEnd, groupEnd));
	}
	const sortedBoundaries = Array.from(rangeBoundaries.values()).sort((a, b) => a - b);
	for (let i = 0; i < sortedBoundaries.length - 1; i++) {
		const start = sortedBoundaries[i];
		const end = sortedBoundaries[i + 1];
		ranges.push({
			offset: Math.floor(start),
			count: Math.floor(end - start)
		});
	}
	return ranges;
}
function hasGroupGaps(geometry, range) {
	const vertexCount = getTriCount(geometry);
	const groups = getRootIndexRanges(geometry, range).sort((a, b) => a.offset - b.offset);
	const finalGroup = groups[groups.length - 1];
	finalGroup.count = Math.min(vertexCount - finalGroup.offset, finalGroup.count);
	let total = 0;
	groups.forEach(({ count }) => total += count);
	return vertexCount !== total;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/computeBoundsUtils.js
function getBounds(triangleBounds, offset, count, target, centroidTarget) {
	let minx = Infinity;
	let miny = Infinity;
	let minz = Infinity;
	let maxx = -Infinity;
	let maxy = -Infinity;
	let maxz = -Infinity;
	let cminx = Infinity;
	let cminy = Infinity;
	let cminz = Infinity;
	let cmaxx = -Infinity;
	let cmaxy = -Infinity;
	let cmaxz = -Infinity;
	for (let i = offset * 6, end = (offset + count) * 6; i < end; i += 6) {
		const cx = triangleBounds[i + 0];
		const hx = triangleBounds[i + 1];
		const lx = cx - hx;
		const rx = cx + hx;
		if (lx < minx) minx = lx;
		if (rx > maxx) maxx = rx;
		if (cx < cminx) cminx = cx;
		if (cx > cmaxx) cmaxx = cx;
		const cy = triangleBounds[i + 2];
		const hy = triangleBounds[i + 3];
		const ly = cy - hy;
		const ry = cy + hy;
		if (ly < miny) miny = ly;
		if (ry > maxy) maxy = ry;
		if (cy < cminy) cminy = cy;
		if (cy > cmaxy) cmaxy = cy;
		const cz = triangleBounds[i + 4];
		const hz = triangleBounds[i + 5];
		const lz = cz - hz;
		const rz = cz + hz;
		if (lz < minz) minz = lz;
		if (rz > maxz) maxz = rz;
		if (cz < cminz) cminz = cz;
		if (cz > cmaxz) cmaxz = cz;
	}
	target[0] = minx;
	target[1] = miny;
	target[2] = minz;
	target[3] = maxx;
	target[4] = maxy;
	target[5] = maxz;
	centroidTarget[0] = cminx;
	centroidTarget[1] = cminy;
	centroidTarget[2] = cminz;
	centroidTarget[3] = cmaxx;
	centroidTarget[4] = cmaxy;
	centroidTarget[5] = cmaxz;
}
function computeTriangleBounds(geo, target = null, offset = null, count = null) {
	const posAttr = geo.attributes.position;
	const index = geo.index ? geo.index.array : null;
	const triCount = getTriCount(geo);
	const normalized = posAttr.normalized;
	let triangleBounds;
	if (target === null) {
		triangleBounds = new Float32Array(triCount * 6);
		offset = 0;
		count = triCount;
	} else {
		triangleBounds = target;
		offset = offset || 0;
		count = count || triCount;
	}
	const posArr = posAttr.array;
	const bufferOffset = posAttr.offset || 0;
	let stride = 3;
	if (posAttr.isInterleavedBufferAttribute) stride = posAttr.data.stride;
	const getters = [
		"getX",
		"getY",
		"getZ"
	];
	for (let tri = offset; tri < offset + count; tri++) {
		const tri3 = tri * 3;
		const tri6 = tri * 6;
		let ai = tri3 + 0;
		let bi = tri3 + 1;
		let ci = tri3 + 2;
		if (index) {
			ai = index[ai];
			bi = index[bi];
			ci = index[ci];
		}
		if (!normalized) {
			ai = ai * stride + bufferOffset;
			bi = bi * stride + bufferOffset;
			ci = ci * stride + bufferOffset;
		}
		for (let el = 0; el < 3; el++) {
			let a, b, c;
			if (normalized) {
				a = posAttr[getters[el]](ai);
				b = posAttr[getters[el]](bi);
				c = posAttr[getters[el]](ci);
			} else {
				a = posArr[ai + el];
				b = posArr[bi + el];
				c = posArr[ci + el];
			}
			let min = a;
			if (b < min) min = b;
			if (c < min) min = c;
			let max = a;
			if (b > max) max = b;
			if (c > max) max = c;
			const halfExtents = (max - min) / 2;
			const el2 = el * 2;
			triangleBounds[tri6 + el2 + 0] = min + halfExtents;
			triangleBounds[tri6 + el2 + 1] = halfExtents + (Math.abs(min) + halfExtents) * FLOAT32_EPSILON;
		}
	}
	return triangleBounds;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/ArrayBoxUtilities.js
function arrayToBox(nodeIndex32, array, target) {
	target.min.x = array[nodeIndex32];
	target.min.y = array[nodeIndex32 + 1];
	target.min.z = array[nodeIndex32 + 2];
	target.max.x = array[nodeIndex32 + 3];
	target.max.y = array[nodeIndex32 + 4];
	target.max.z = array[nodeIndex32 + 5];
	return target;
}
function getLongestEdgeIndex(bounds) {
	let splitDimIdx = -1;
	let splitDist = -Infinity;
	for (let i = 0; i < 3; i++) {
		const dist = bounds[i + 3] - bounds[i];
		if (dist > splitDist) {
			splitDist = dist;
			splitDimIdx = i;
		}
	}
	return splitDimIdx;
}
function copyBounds(source, target) {
	target.set(source);
}
function unionBounds(a, b, target) {
	let aVal, bVal;
	for (let d = 0; d < 3; d++) {
		const d3 = d + 3;
		aVal = a[d];
		bVal = b[d];
		target[d] = aVal < bVal ? aVal : bVal;
		aVal = a[d3];
		bVal = b[d3];
		target[d3] = aVal > bVal ? aVal : bVal;
	}
}
function expandByTriangleBounds(startIndex, triangleBounds, bounds) {
	for (let d = 0; d < 3; d++) {
		const tCenter = triangleBounds[startIndex + 2 * d];
		const tHalf = triangleBounds[startIndex + 2 * d + 1];
		const tMin = tCenter - tHalf;
		const tMax = tCenter + tHalf;
		if (tMin < bounds[d]) bounds[d] = tMin;
		if (tMax > bounds[d + 3]) bounds[d + 3] = tMax;
	}
}
function computeSurfaceArea(bounds) {
	const d0 = bounds[3] - bounds[0];
	const d1 = bounds[4] - bounds[1];
	const d2 = bounds[5] - bounds[2];
	return 2 * (d0 * d1 + d1 * d2 + d2 * d0);
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/splitUtils.js
var BIN_COUNT = 32;
var binsSort = (a, b) => a.candidate - b.candidate;
var sahBins = new Array(BIN_COUNT).fill().map(() => {
	return {
		count: 0,
		bounds: new Float32Array(6),
		rightCacheBounds: new Float32Array(6),
		leftCacheBounds: new Float32Array(6),
		candidate: 0
	};
});
var leftBounds = new Float32Array(6);
function getOptimalSplit(nodeBoundingData, centroidBoundingData, triangleBounds, offset, count, strategy) {
	let axis = -1;
	let pos = 0;
	if (strategy === 0) {
		axis = getLongestEdgeIndex(centroidBoundingData);
		if (axis !== -1) pos = (centroidBoundingData[axis] + centroidBoundingData[axis + 3]) / 2;
	} else if (strategy === 1) {
		axis = getLongestEdgeIndex(nodeBoundingData);
		if (axis !== -1) pos = getAverage(triangleBounds, offset, count, axis);
	} else if (strategy === 2) {
		const rootSurfaceArea = computeSurfaceArea(nodeBoundingData);
		let bestCost = TRIANGLE_INTERSECT_COST * count;
		const cStart = offset * 6;
		const cEnd = (offset + count) * 6;
		for (let a = 0; a < 3; a++) {
			const axisLeft = centroidBoundingData[a];
			const binWidth = (centroidBoundingData[a + 3] - axisLeft) / BIN_COUNT;
			if (count < BIN_COUNT / 4) {
				const truncatedBins = [...sahBins];
				truncatedBins.length = count;
				let b = 0;
				for (let c = cStart; c < cEnd; c += 6, b++) {
					const bin = truncatedBins[b];
					bin.candidate = triangleBounds[c + 2 * a];
					bin.count = 0;
					const { bounds, leftCacheBounds, rightCacheBounds } = bin;
					for (let d = 0; d < 3; d++) {
						rightCacheBounds[d] = Infinity;
						rightCacheBounds[d + 3] = -Infinity;
						leftCacheBounds[d] = Infinity;
						leftCacheBounds[d + 3] = -Infinity;
						bounds[d] = Infinity;
						bounds[d + 3] = -Infinity;
					}
					expandByTriangleBounds(c, triangleBounds, bounds);
				}
				truncatedBins.sort(binsSort);
				let splitCount = count;
				for (let bi = 0; bi < splitCount; bi++) {
					const bin = truncatedBins[bi];
					while (bi + 1 < splitCount && truncatedBins[bi + 1].candidate === bin.candidate) {
						truncatedBins.splice(bi + 1, 1);
						splitCount--;
					}
				}
				for (let c = cStart; c < cEnd; c += 6) {
					const center = triangleBounds[c + 2 * a];
					for (let bi = 0; bi < splitCount; bi++) {
						const bin = truncatedBins[bi];
						if (center >= bin.candidate) expandByTriangleBounds(c, triangleBounds, bin.rightCacheBounds);
						else {
							expandByTriangleBounds(c, triangleBounds, bin.leftCacheBounds);
							bin.count++;
						}
					}
				}
				for (let bi = 0; bi < splitCount; bi++) {
					const bin = truncatedBins[bi];
					const leftCount = bin.count;
					const rightCount = count - bin.count;
					const leftBounds = bin.leftCacheBounds;
					const rightBounds = bin.rightCacheBounds;
					let leftProb = 0;
					if (leftCount !== 0) leftProb = computeSurfaceArea(leftBounds) / rootSurfaceArea;
					let rightProb = 0;
					if (rightCount !== 0) rightProb = computeSurfaceArea(rightBounds) / rootSurfaceArea;
					const cost = 1 + TRIANGLE_INTERSECT_COST * (leftProb * leftCount + rightProb * rightCount);
					if (cost < bestCost) {
						axis = a;
						bestCost = cost;
						pos = bin.candidate;
					}
				}
			} else {
				for (let i = 0; i < BIN_COUNT; i++) {
					const bin = sahBins[i];
					bin.count = 0;
					bin.candidate = axisLeft + binWidth + i * binWidth;
					const bounds = bin.bounds;
					for (let d = 0; d < 3; d++) {
						bounds[d] = Infinity;
						bounds[d + 3] = -Infinity;
					}
				}
				for (let c = cStart; c < cEnd; c += 6) {
					let binIndex = ~~((triangleBounds[c + 2 * a] - axisLeft) / binWidth);
					if (binIndex >= BIN_COUNT) binIndex = BIN_COUNT - 1;
					const bin = sahBins[binIndex];
					bin.count++;
					expandByTriangleBounds(c, triangleBounds, bin.bounds);
				}
				const lastBin = sahBins[BIN_COUNT - 1];
				copyBounds(lastBin.bounds, lastBin.rightCacheBounds);
				for (let i = BIN_COUNT - 2; i >= 0; i--) {
					const bin = sahBins[i];
					const nextBin = sahBins[i + 1];
					unionBounds(bin.bounds, nextBin.rightCacheBounds, bin.rightCacheBounds);
				}
				let leftCount = 0;
				for (let i = 0; i < BIN_COUNT - 1; i++) {
					const bin = sahBins[i];
					const binCount = bin.count;
					const bounds = bin.bounds;
					const rightBounds = sahBins[i + 1].rightCacheBounds;
					if (binCount !== 0) if (leftCount === 0) copyBounds(bounds, leftBounds);
					else unionBounds(bounds, leftBounds, leftBounds);
					leftCount += binCount;
					let leftProb = 0;
					let rightProb = 0;
					if (leftCount !== 0) leftProb = computeSurfaceArea(leftBounds) / rootSurfaceArea;
					const rightCount = count - leftCount;
					if (rightCount !== 0) rightProb = computeSurfaceArea(rightBounds) / rootSurfaceArea;
					const cost = 1 + TRIANGLE_INTERSECT_COST * (leftProb * leftCount + rightProb * rightCount);
					if (cost < bestCost) {
						axis = a;
						bestCost = cost;
						pos = bin.candidate;
					}
				}
			}
		}
	} else console.warn(`MeshBVH: Invalid build strategy value ${strategy} used.`);
	return {
		axis,
		pos
	};
}
function getAverage(triangleBounds, offset, count, axis) {
	let avg = 0;
	for (let i = offset, end = offset + count; i < end; i++) avg += triangleBounds[i * 6 + axis * 2];
	return avg / count;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/MeshBVHNode.js
var MeshBVHNode = class {
	constructor() {
		this.boundingData = new Float32Array(6);
	}
};
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/sortUtils.generated.js
function partition(indirectBuffer, index, triangleBounds, offset, count, split) {
	let left = offset;
	let right = offset + count - 1;
	const pos = split.pos;
	const axisOffset = split.axis * 2;
	while (true) {
		while (left <= right && triangleBounds[left * 6 + axisOffset] < pos) left++;
		while (left <= right && triangleBounds[right * 6 + axisOffset] >= pos) right--;
		if (left < right) {
			for (let i = 0; i < 3; i++) {
				let t0 = index[left * 3 + i];
				index[left * 3 + i] = index[right * 3 + i];
				index[right * 3 + i] = t0;
			}
			for (let i = 0; i < 6; i++) {
				let tb = triangleBounds[left * 6 + i];
				triangleBounds[left * 6 + i] = triangleBounds[right * 6 + i];
				triangleBounds[right * 6 + i] = tb;
			}
			left++;
			right--;
		} else return left;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/sortUtils_indirect.generated.js
function partition_indirect(indirectBuffer, index, triangleBounds, offset, count, split) {
	let left = offset;
	let right = offset + count - 1;
	const pos = split.pos;
	const axisOffset = split.axis * 2;
	while (true) {
		while (left <= right && triangleBounds[left * 6 + axisOffset] < pos) left++;
		while (left <= right && triangleBounds[right * 6 + axisOffset] >= pos) right--;
		if (left < right) {
			let t = indirectBuffer[left];
			indirectBuffer[left] = indirectBuffer[right];
			indirectBuffer[right] = t;
			for (let i = 0; i < 6; i++) {
				let tb = triangleBounds[left * 6 + i];
				triangleBounds[left * 6 + i] = triangleBounds[right * 6 + i];
				triangleBounds[right * 6 + i] = tb;
			}
			left++;
			right--;
		} else return left;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/utils/nodeBufferUtils.js
function IS_LEAF(n16, uint16Array) {
	return uint16Array[n16 + 15] === 65535;
}
function OFFSET(n32, uint32Array) {
	return uint32Array[n32 + 6];
}
function COUNT(n16, uint16Array) {
	return uint16Array[n16 + 14];
}
function LEFT_NODE(n32) {
	return n32 + 8;
}
function RIGHT_NODE(n32, uint32Array) {
	return uint32Array[n32 + 6];
}
function SPLIT_AXIS(n32, uint32Array) {
	return uint32Array[n32 + 7];
}
function BOUNDING_DATA_INDEX(n32) {
	return n32;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/buildUtils.js
var float32Array, uint32Array, uint16Array, uint8Array;
var MAX_POINTER = Math.pow(2, 32);
function countNodes(node) {
	if ("count" in node) return 1;
	else return 1 + countNodes(node.left) + countNodes(node.right);
}
function populateBuffer(byteOffset, node, buffer) {
	float32Array = new Float32Array(buffer);
	uint32Array = new Uint32Array(buffer);
	uint16Array = new Uint16Array(buffer);
	uint8Array = new Uint8Array(buffer);
	return _populateBuffer(byteOffset, node);
}
function _populateBuffer(byteOffset, node) {
	const stride4Offset = byteOffset / 4;
	const stride2Offset = byteOffset / 2;
	const isLeaf = "count" in node;
	const boundingData = node.boundingData;
	for (let i = 0; i < 6; i++) float32Array[stride4Offset + i] = boundingData[i];
	if (isLeaf) if (node.buffer) {
		const buffer = node.buffer;
		uint8Array.set(new Uint8Array(buffer), byteOffset);
		for (let offset = byteOffset, l = byteOffset + buffer.byteLength; offset < l; offset += 32) if (!IS_LEAF(offset / 2, uint16Array)) uint32Array[offset / 4 + 6] += stride4Offset;
		return byteOffset + buffer.byteLength;
	} else {
		const offset = node.offset;
		const count = node.count;
		uint32Array[stride4Offset + 6] = offset;
		uint16Array[stride2Offset + 14] = count;
		uint16Array[stride2Offset + 15] = IS_LEAFNODE_FLAG;
		return byteOffset + 32;
	}
	else {
		const left = node.left;
		const right = node.right;
		const splitAxis = node.splitAxis;
		let nextUnusedPointer;
		nextUnusedPointer = _populateBuffer(byteOffset + 32, left);
		if (nextUnusedPointer / 4 > MAX_POINTER) throw new Error("MeshBVH: Cannot store child pointer greater than 32 bits.");
		uint32Array[stride4Offset + 6] = nextUnusedPointer / 4;
		nextUnusedPointer = _populateBuffer(nextUnusedPointer, right);
		uint32Array[stride4Offset + 7] = splitAxis;
		return nextUnusedPointer;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/build/buildTree.js
function generateIndirectBuffer(geometry, useSharedArrayBuffer) {
	const triCount = (geometry.index ? geometry.index.count : geometry.attributes.position.count) / 3;
	const useUint32 = triCount > 2 ** 16;
	const byteCount = useUint32 ? 4 : 2;
	const buffer = useSharedArrayBuffer ? new SharedArrayBuffer(triCount * byteCount) : new ArrayBuffer(triCount * byteCount);
	const indirectBuffer = useUint32 ? new Uint32Array(buffer) : new Uint16Array(buffer);
	for (let i = 0, l = indirectBuffer.length; i < l; i++) indirectBuffer[i] = i;
	return indirectBuffer;
}
function buildTree(bvh, triangleBounds, offset, count, options) {
	const { maxDepth, verbose, maxLeafTris, strategy, onProgress, indirect } = options;
	const indirectBuffer = bvh._indirectBuffer;
	const geometry = bvh.geometry;
	const indexArray = geometry.index ? geometry.index.array : null;
	const partionFunc = indirect ? partition_indirect : partition;
	const totalTriangles = getTriCount(geometry);
	const cacheCentroidBoundingData = new Float32Array(6);
	let reachedMaxDepth = false;
	const root = new MeshBVHNode();
	getBounds(triangleBounds, offset, count, root.boundingData, cacheCentroidBoundingData);
	splitNode(root, offset, count, cacheCentroidBoundingData);
	return root;
	function triggerProgress(trianglesProcessed) {
		if (onProgress) onProgress(trianglesProcessed / totalTriangles);
	}
	function splitNode(node, offset, count, centroidBoundingData = null, depth = 0) {
		if (!reachedMaxDepth && depth >= maxDepth) {
			reachedMaxDepth = true;
			if (verbose) {
				console.warn(`MeshBVH: Max depth of ${maxDepth} reached when generating BVH. Consider increasing maxDepth.`);
				console.warn(geometry);
			}
		}
		if (count <= maxLeafTris || depth >= maxDepth) {
			triggerProgress(offset + count);
			node.offset = offset;
			node.count = count;
			return node;
		}
		const split = getOptimalSplit(node.boundingData, centroidBoundingData, triangleBounds, offset, count, strategy);
		if (split.axis === -1) {
			triggerProgress(offset + count);
			node.offset = offset;
			node.count = count;
			return node;
		}
		const splitOffset = partionFunc(indirectBuffer, indexArray, triangleBounds, offset, count, split);
		if (splitOffset === offset || splitOffset === offset + count) {
			triggerProgress(offset + count);
			node.offset = offset;
			node.count = count;
		} else {
			node.splitAxis = split.axis;
			const left = new MeshBVHNode();
			const lstart = offset;
			const lcount = splitOffset - offset;
			node.left = left;
			getBounds(triangleBounds, lstart, lcount, left.boundingData, cacheCentroidBoundingData);
			splitNode(left, lstart, lcount, cacheCentroidBoundingData, depth + 1);
			const right = new MeshBVHNode();
			const rstart = splitOffset;
			const rcount = count - lcount;
			node.right = right;
			getBounds(triangleBounds, rstart, rcount, right.boundingData, cacheCentroidBoundingData);
			splitNode(right, rstart, rcount, cacheCentroidBoundingData, depth + 1);
		}
		return node;
	}
}
function buildPackedTree(bvh, options) {
	const geometry = bvh.geometry;
	if (options.indirect) {
		bvh._indirectBuffer = generateIndirectBuffer(geometry, options.useSharedArrayBuffer);
		if (hasGroupGaps(geometry, options.range) && !options.verbose) console.warn("MeshBVH: Provided geometry contains groups or a range that do not fully span the vertex contents while using the \"indirect\" option. BVH may incorrectly report intersections on unrendered portions of the geometry.");
	}
	if (!bvh._indirectBuffer) ensureIndex(geometry, options);
	const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;
	const triangleBounds = computeTriangleBounds(geometry);
	bvh._roots = (options.indirect ? getFullGeometryRange(geometry, options.range) : getRootIndexRanges(geometry, options.range)).map((range) => {
		const root = buildTree(bvh, triangleBounds, range.offset, range.count, options);
		const buffer = new BufferConstructor(32 * countNodes(root));
		populateBuffer(0, root, buffer);
		return buffer;
	});
}
//#endregion
//#region node_modules/three-mesh-bvh/src/math/SeparatingAxisBounds.js
var SeparatingAxisBounds = class {
	constructor() {
		this.min = Infinity;
		this.max = -Infinity;
	}
	setFromPointsField(points, field) {
		let min = Infinity;
		let max = -Infinity;
		for (let i = 0, l = points.length; i < l; i++) {
			const val = points[i][field];
			min = val < min ? val : min;
			max = val > max ? val : max;
		}
		this.min = min;
		this.max = max;
	}
	setFromPoints(axis, points) {
		let min = Infinity;
		let max = -Infinity;
		for (let i = 0, l = points.length; i < l; i++) {
			const p = points[i];
			const val = axis.dot(p);
			min = val < min ? val : min;
			max = val > max ? val : max;
		}
		this.min = min;
		this.max = max;
	}
	isSeparated(other) {
		return this.min > other.max || other.min > this.max;
	}
};
SeparatingAxisBounds.prototype.setFromBox = (function() {
	const p = new Vector3();
	return function setFromBox(axis, box) {
		const boxMin = box.min;
		const boxMax = box.max;
		let min = Infinity;
		let max = -Infinity;
		for (let x = 0; x <= 1; x++) for (let y = 0; y <= 1; y++) for (let z = 0; z <= 1; z++) {
			p.x = boxMin.x * x + boxMax.x * (1 - x);
			p.y = boxMin.y * y + boxMax.y * (1 - y);
			p.z = boxMin.z * z + boxMax.z * (1 - z);
			const val = axis.dot(p);
			min = Math.min(val, min);
			max = Math.max(val, max);
		}
		this.min = min;
		this.max = max;
	};
})();
(function() {
	const cacheSatBounds = new SeparatingAxisBounds();
	return function areIntersecting(shape1, shape2) {
		const points1 = shape1.points;
		const satAxes1 = shape1.satAxes;
		const satBounds1 = shape1.satBounds;
		const points2 = shape2.points;
		const satAxes2 = shape2.satAxes;
		const satBounds2 = shape2.satBounds;
		for (let i = 0; i < 3; i++) {
			const sb = satBounds1[i];
			const sa = satAxes1[i];
			cacheSatBounds.setFromPoints(sa, points2);
			if (sb.isSeparated(cacheSatBounds)) return false;
		}
		for (let i = 0; i < 3; i++) {
			const sb = satBounds2[i];
			const sa = satAxes2[i];
			cacheSatBounds.setFromPoints(sa, points1);
			if (sb.isSeparated(cacheSatBounds)) return false;
		}
	};
})();
//#endregion
//#region node_modules/three-mesh-bvh/src/math/MathUtilities.js
var closestPointLineToLine = (function() {
	const dir1 = new Vector3();
	const dir2 = new Vector3();
	const v02 = new Vector3();
	return function closestPointLineToLine(l1, l2, result) {
		const v0 = l1.start;
		const v10 = dir1;
		const v2 = l2.start;
		const v32 = dir2;
		v02.subVectors(v0, v2);
		dir1.subVectors(l1.end, l1.start);
		dir2.subVectors(l2.end, l2.start);
		const d0232 = v02.dot(v32);
		const d3210 = v32.dot(v10);
		const d3232 = v32.dot(v32);
		const d0210 = v02.dot(v10);
		const denom = v10.dot(v10) * d3232 - d3210 * d3210;
		let d, d2;
		if (denom !== 0) d = (d0232 * d3210 - d0210 * d3232) / denom;
		else d = 0;
		d2 = (d0232 + d * d3210) / d3232;
		result.x = d;
		result.y = d2;
	};
})();
var closestPointsSegmentToSegment = (function() {
	const paramResult = new Vector2();
	const temp1 = new Vector3();
	const temp2 = new Vector3();
	return function closestPointsSegmentToSegment(l1, l2, target1, target2) {
		closestPointLineToLine(l1, l2, paramResult);
		let d = paramResult.x;
		let d2 = paramResult.y;
		if (d >= 0 && d <= 1 && d2 >= 0 && d2 <= 1) {
			l1.at(d, target1);
			l2.at(d2, target2);
			return;
		} else if (d >= 0 && d <= 1) {
			if (d2 < 0) l2.at(0, target2);
			else l2.at(1, target2);
			l1.closestPointToPoint(target2, true, target1);
			return;
		} else if (d2 >= 0 && d2 <= 1) {
			if (d < 0) l1.at(0, target1);
			else l1.at(1, target1);
			l2.closestPointToPoint(target1, true, target2);
			return;
		} else {
			let p;
			if (d < 0) p = l1.start;
			else p = l1.end;
			let p2;
			if (d2 < 0) p2 = l2.start;
			else p2 = l2.end;
			const closestPoint = temp1;
			const closestPoint2 = temp2;
			l1.closestPointToPoint(p2, true, temp1);
			l2.closestPointToPoint(p, true, temp2);
			if (closestPoint.distanceToSquared(p2) <= closestPoint2.distanceToSquared(p)) {
				target1.copy(closestPoint);
				target2.copy(p2);
				return;
			} else {
				target1.copy(p);
				target2.copy(closestPoint2);
				return;
			}
		}
	};
})();
var sphereIntersectTriangle = (function() {
	const closestPointTemp = new Vector3();
	const projectedPointTemp = new Vector3();
	const planeTemp = new Plane$1();
	const lineTemp = new Line3();
	return function sphereIntersectTriangle(sphere, triangle) {
		const { radius, center } = sphere;
		const { a, b, c } = triangle;
		lineTemp.start = a;
		lineTemp.end = b;
		if (lineTemp.closestPointToPoint(center, true, closestPointTemp).distanceTo(center) <= radius) return true;
		lineTemp.start = a;
		lineTemp.end = c;
		if (lineTemp.closestPointToPoint(center, true, closestPointTemp).distanceTo(center) <= radius) return true;
		lineTemp.start = b;
		lineTemp.end = c;
		if (lineTemp.closestPointToPoint(center, true, closestPointTemp).distanceTo(center) <= radius) return true;
		const plane = triangle.getPlane(planeTemp);
		if (Math.abs(plane.distanceToPoint(center)) <= radius) {
			const pp = plane.projectPoint(center, projectedPointTemp);
			if (triangle.containsPoint(pp)) return true;
		}
		return false;
	};
})();
//#endregion
//#region node_modules/three-mesh-bvh/src/math/ExtendedTriangle.js
var ZERO_EPSILON = 1e-15;
function isNearZero(value) {
	return Math.abs(value) < ZERO_EPSILON;
}
var ExtendedTriangle = class extends Triangle {
	constructor(...args) {
		super(...args);
		this.isExtendedTriangle = true;
		this.satAxes = new Array(4).fill().map(() => new Vector3());
		this.satBounds = new Array(4).fill().map(() => new SeparatingAxisBounds());
		this.points = [
			this.a,
			this.b,
			this.c
		];
		this.sphere = new Sphere$1();
		this.plane = new Plane$1();
		this.needsUpdate = true;
	}
	intersectsSphere(sphere) {
		return sphereIntersectTriangle(sphere, this);
	}
	update() {
		const a = this.a;
		const b = this.b;
		const c = this.c;
		const points = this.points;
		const satAxes = this.satAxes;
		const satBounds = this.satBounds;
		const axis0 = satAxes[0];
		const sab0 = satBounds[0];
		this.getNormal(axis0);
		sab0.setFromPoints(axis0, points);
		const axis1 = satAxes[1];
		const sab1 = satBounds[1];
		axis1.subVectors(a, b);
		sab1.setFromPoints(axis1, points);
		const axis2 = satAxes[2];
		const sab2 = satBounds[2];
		axis2.subVectors(b, c);
		sab2.setFromPoints(axis2, points);
		const axis3 = satAxes[3];
		const sab3 = satBounds[3];
		axis3.subVectors(c, a);
		sab3.setFromPoints(axis3, points);
		this.sphere.setFromPoints(this.points);
		this.plane.setFromNormalAndCoplanarPoint(axis0, a);
		this.needsUpdate = false;
	}
};
ExtendedTriangle.prototype.closestPointToSegment = (function() {
	const point1 = new Vector3();
	const point2 = new Vector3();
	const edge = new Line3();
	return function distanceToSegment(segment, target1 = null, target2 = null) {
		const { start, end } = segment;
		const points = this.points;
		let distSq;
		let closestDistanceSq = Infinity;
		for (let i = 0; i < 3; i++) {
			const nexti = (i + 1) % 3;
			edge.start.copy(points[i]);
			edge.end.copy(points[nexti]);
			closestPointsSegmentToSegment(edge, segment, point1, point2);
			distSq = point1.distanceToSquared(point2);
			if (distSq < closestDistanceSq) {
				closestDistanceSq = distSq;
				if (target1) target1.copy(point1);
				if (target2) target2.copy(point2);
			}
		}
		this.closestPointToPoint(start, point1);
		distSq = start.distanceToSquared(point1);
		if (distSq < closestDistanceSq) {
			closestDistanceSq = distSq;
			if (target1) target1.copy(point1);
			if (target2) target2.copy(start);
		}
		this.closestPointToPoint(end, point1);
		distSq = end.distanceToSquared(point1);
		if (distSq < closestDistanceSq) {
			closestDistanceSq = distSq;
			if (target1) target1.copy(point1);
			if (target2) target2.copy(end);
		}
		return Math.sqrt(closestDistanceSq);
	};
})();
ExtendedTriangle.prototype.intersectsTriangle = (function() {
	const saTri2 = new ExtendedTriangle();
	const arr1 = new Array(3);
	const arr2 = new Array(3);
	const cachedSatBounds = new SeparatingAxisBounds();
	const cachedSatBounds2 = new SeparatingAxisBounds();
	const cachedAxis = new Vector3();
	const dir = new Vector3();
	const dir1 = new Vector3();
	const dir2 = new Vector3();
	const tempDir = new Vector3();
	const edge = new Line3();
	const edge1 = new Line3();
	const edge2 = new Line3();
	const tempPoint = new Vector3();
	function triIntersectPlane(tri, plane, targetEdge) {
		const points = tri.points;
		let count = 0;
		let startPointIntersection = -1;
		for (let i = 0; i < 3; i++) {
			const { start, end } = edge;
			start.copy(points[i]);
			end.copy(points[(i + 1) % 3]);
			edge.delta(dir);
			const startIntersects = isNearZero(plane.distanceToPoint(start));
			if (isNearZero(plane.normal.dot(dir)) && startIntersects) {
				targetEdge.copy(edge);
				count = 2;
				break;
			}
			const doesIntersect = plane.intersectLine(edge, tempPoint);
			if (!doesIntersect && startIntersects) tempPoint.copy(start);
			if ((doesIntersect || startIntersects) && !isNearZero(tempPoint.distanceTo(end))) {
				if (count <= 1) {
					(count === 1 ? targetEdge.start : targetEdge.end).copy(tempPoint);
					if (startIntersects) startPointIntersection = count;
				} else if (count >= 2) {
					(startPointIntersection === 1 ? targetEdge.start : targetEdge.end).copy(tempPoint);
					count = 2;
					break;
				}
				count++;
				if (count === 2 && startPointIntersection === -1) break;
			}
		}
		return count;
	}
	return function intersectsTriangle(other, target = null, suppressLog = false) {
		if (this.needsUpdate) this.update();
		if (!other.isExtendedTriangle) {
			saTri2.copy(other);
			saTri2.update();
			other = saTri2;
		} else if (other.needsUpdate) other.update();
		const plane1 = this.plane;
		const plane2 = other.plane;
		if (Math.abs(plane1.normal.dot(plane2.normal)) > .9999999999) {
			const satBounds1 = this.satBounds;
			const satAxes1 = this.satAxes;
			arr2[0] = other.a;
			arr2[1] = other.b;
			arr2[2] = other.c;
			for (let i = 0; i < 4; i++) {
				const sb = satBounds1[i];
				const sa = satAxes1[i];
				cachedSatBounds.setFromPoints(sa, arr2);
				if (sb.isSeparated(cachedSatBounds)) return false;
			}
			const satBounds2 = other.satBounds;
			const satAxes2 = other.satAxes;
			arr1[0] = this.a;
			arr1[1] = this.b;
			arr1[2] = this.c;
			for (let i = 0; i < 4; i++) {
				const sb = satBounds2[i];
				const sa = satAxes2[i];
				cachedSatBounds.setFromPoints(sa, arr1);
				if (sb.isSeparated(cachedSatBounds)) return false;
			}
			for (let i = 0; i < 4; i++) {
				const sa1 = satAxes1[i];
				for (let i2 = 0; i2 < 4; i2++) {
					const sa2 = satAxes2[i2];
					cachedAxis.crossVectors(sa1, sa2);
					cachedSatBounds.setFromPoints(cachedAxis, arr1);
					cachedSatBounds2.setFromPoints(cachedAxis, arr2);
					if (cachedSatBounds.isSeparated(cachedSatBounds2)) return false;
				}
			}
			if (target) {
				if (!suppressLog) console.warn("ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0.");
				target.start.set(0, 0, 0);
				target.end.set(0, 0, 0);
			}
			return true;
		} else {
			const count1 = triIntersectPlane(this, plane2, edge1);
			if (count1 === 1 && other.containsPoint(edge1.end)) {
				if (target) {
					target.start.copy(edge1.end);
					target.end.copy(edge1.end);
				}
				return true;
			} else if (count1 !== 2) return false;
			const count2 = triIntersectPlane(other, plane1, edge2);
			if (count2 === 1 && this.containsPoint(edge2.end)) {
				if (target) {
					target.start.copy(edge2.end);
					target.end.copy(edge2.end);
				}
				return true;
			} else if (count2 !== 2) return false;
			edge1.delta(dir1);
			edge2.delta(dir2);
			if (dir1.dot(dir2) < 0) {
				let tmp = edge2.start;
				edge2.start = edge2.end;
				edge2.end = tmp;
			}
			const s1 = edge1.start.dot(dir1);
			const e1 = edge1.end.dot(dir1);
			const s2 = edge2.start.dot(dir1);
			const e2 = edge2.end.dot(dir1);
			if (s1 !== e2 && s2 !== e1 && e1 < s2 === s1 < e2) return false;
			if (target) {
				tempDir.subVectors(edge1.start, edge2.start);
				if (tempDir.dot(dir1) > 0) target.start.copy(edge1.start);
				else target.start.copy(edge2.start);
				tempDir.subVectors(edge1.end, edge2.end);
				if (tempDir.dot(dir1) < 0) target.end.copy(edge1.end);
				else target.end.copy(edge2.end);
			}
			return true;
		}
	};
})();
ExtendedTriangle.prototype.distanceToPoint = (function() {
	const target = new Vector3();
	return function distanceToPoint(point) {
		this.closestPointToPoint(point, target);
		return point.distanceTo(target);
	};
})();
ExtendedTriangle.prototype.distanceToTriangle = (function() {
	const point = new Vector3();
	const point2 = new Vector3();
	const cornerFields = [
		"a",
		"b",
		"c"
	];
	const line1 = new Line3();
	const line2 = new Line3();
	return function distanceToTriangle(other, target1 = null, target2 = null) {
		const lineTarget = target1 || target2 ? line1 : null;
		if (this.intersectsTriangle(other, lineTarget)) {
			if (target1 || target2) {
				if (target1) lineTarget.getCenter(target1);
				if (target2) lineTarget.getCenter(target2);
			}
			return 0;
		}
		let closestDistanceSq = Infinity;
		for (let i = 0; i < 3; i++) {
			let dist;
			const field = cornerFields[i];
			const otherVec = other[field];
			this.closestPointToPoint(otherVec, point);
			dist = otherVec.distanceToSquared(point);
			if (dist < closestDistanceSq) {
				closestDistanceSq = dist;
				if (target1) target1.copy(point);
				if (target2) target2.copy(otherVec);
			}
			const thisVec = this[field];
			other.closestPointToPoint(thisVec, point);
			dist = thisVec.distanceToSquared(point);
			if (dist < closestDistanceSq) {
				closestDistanceSq = dist;
				if (target1) target1.copy(thisVec);
				if (target2) target2.copy(point);
			}
		}
		for (let i = 0; i < 3; i++) {
			const f11 = cornerFields[i];
			const f12 = cornerFields[(i + 1) % 3];
			line1.set(this[f11], this[f12]);
			for (let i2 = 0; i2 < 3; i2++) {
				const f21 = cornerFields[i2];
				const f22 = cornerFields[(i2 + 1) % 3];
				line2.set(other[f21], other[f22]);
				closestPointsSegmentToSegment(line1, line2, point, point2);
				const dist = point.distanceToSquared(point2);
				if (dist < closestDistanceSq) {
					closestDistanceSq = dist;
					if (target1) target1.copy(point);
					if (target2) target2.copy(point2);
				}
			}
		}
		return Math.sqrt(closestDistanceSq);
	};
})();
//#endregion
//#region node_modules/three-mesh-bvh/src/math/OrientedBox.js
var OrientedBox = class {
	constructor(min, max, matrix) {
		this.isOrientedBox = true;
		this.min = new Vector3();
		this.max = new Vector3();
		this.matrix = new Matrix4();
		this.invMatrix = new Matrix4();
		this.points = new Array(8).fill().map(() => new Vector3());
		this.satAxes = new Array(3).fill().map(() => new Vector3());
		this.satBounds = new Array(3).fill().map(() => new SeparatingAxisBounds());
		this.alignedSatBounds = new Array(3).fill().map(() => new SeparatingAxisBounds());
		this.needsUpdate = false;
		if (min) this.min.copy(min);
		if (max) this.max.copy(max);
		if (matrix) this.matrix.copy(matrix);
	}
	set(min, max, matrix) {
		this.min.copy(min);
		this.max.copy(max);
		this.matrix.copy(matrix);
		this.needsUpdate = true;
	}
	copy(other) {
		this.min.copy(other.min);
		this.max.copy(other.max);
		this.matrix.copy(other.matrix);
		this.needsUpdate = true;
	}
};
OrientedBox.prototype.update = (function() {
	return function update() {
		const matrix = this.matrix;
		const min = this.min;
		const max = this.max;
		const points = this.points;
		for (let x = 0; x <= 1; x++) for (let y = 0; y <= 1; y++) for (let z = 0; z <= 1; z++) {
			const v = points[1 * x | 2 * y | 4 * z];
			v.x = x ? max.x : min.x;
			v.y = y ? max.y : min.y;
			v.z = z ? max.z : min.z;
			v.applyMatrix4(matrix);
		}
		const satBounds = this.satBounds;
		const satAxes = this.satAxes;
		const minVec = points[0];
		for (let i = 0; i < 3; i++) {
			const axis = satAxes[i];
			const sb = satBounds[i];
			const pi = points[1 << i];
			axis.subVectors(minVec, pi);
			sb.setFromPoints(axis, points);
		}
		const alignedSatBounds = this.alignedSatBounds;
		alignedSatBounds[0].setFromPointsField(points, "x");
		alignedSatBounds[1].setFromPointsField(points, "y");
		alignedSatBounds[2].setFromPointsField(points, "z");
		this.invMatrix.copy(this.matrix).invert();
		this.needsUpdate = false;
	};
})();
OrientedBox.prototype.intersectsBox = (function() {
	const aabbBounds = new SeparatingAxisBounds();
	return function intersectsBox(box) {
		if (this.needsUpdate) this.update();
		const min = box.min;
		const max = box.max;
		const satBounds = this.satBounds;
		const satAxes = this.satAxes;
		const alignedSatBounds = this.alignedSatBounds;
		aabbBounds.min = min.x;
		aabbBounds.max = max.x;
		if (alignedSatBounds[0].isSeparated(aabbBounds)) return false;
		aabbBounds.min = min.y;
		aabbBounds.max = max.y;
		if (alignedSatBounds[1].isSeparated(aabbBounds)) return false;
		aabbBounds.min = min.z;
		aabbBounds.max = max.z;
		if (alignedSatBounds[2].isSeparated(aabbBounds)) return false;
		for (let i = 0; i < 3; i++) {
			const axis = satAxes[i];
			const sb = satBounds[i];
			aabbBounds.setFromBox(axis, box);
			if (sb.isSeparated(aabbBounds)) return false;
		}
		return true;
	};
})();
OrientedBox.prototype.intersectsTriangle = (function() {
	const saTri = new ExtendedTriangle();
	const pointsArr = new Array(3);
	const cachedSatBounds = new SeparatingAxisBounds();
	const cachedSatBounds2 = new SeparatingAxisBounds();
	const cachedAxis = new Vector3();
	return function intersectsTriangle(triangle) {
		if (this.needsUpdate) this.update();
		if (!triangle.isExtendedTriangle) {
			saTri.copy(triangle);
			saTri.update();
			triangle = saTri;
		} else if (triangle.needsUpdate) triangle.update();
		const satBounds = this.satBounds;
		const satAxes = this.satAxes;
		pointsArr[0] = triangle.a;
		pointsArr[1] = triangle.b;
		pointsArr[2] = triangle.c;
		for (let i = 0; i < 3; i++) {
			const sb = satBounds[i];
			const sa = satAxes[i];
			cachedSatBounds.setFromPoints(sa, pointsArr);
			if (sb.isSeparated(cachedSatBounds)) return false;
		}
		const triSatBounds = triangle.satBounds;
		const triSatAxes = triangle.satAxes;
		const points = this.points;
		for (let i = 0; i < 3; i++) {
			const sb = triSatBounds[i];
			const sa = triSatAxes[i];
			cachedSatBounds.setFromPoints(sa, points);
			if (sb.isSeparated(cachedSatBounds)) return false;
		}
		for (let i = 0; i < 3; i++) {
			const sa1 = satAxes[i];
			for (let i2 = 0; i2 < 4; i2++) {
				const sa2 = triSatAxes[i2];
				cachedAxis.crossVectors(sa1, sa2);
				cachedSatBounds.setFromPoints(cachedAxis, pointsArr);
				cachedSatBounds2.setFromPoints(cachedAxis, points);
				if (cachedSatBounds.isSeparated(cachedSatBounds2)) return false;
			}
		}
		return true;
	};
})();
OrientedBox.prototype.closestPointToPoint = (function() {
	return function closestPointToPoint(point, target1) {
		if (this.needsUpdate) this.update();
		target1.copy(point).applyMatrix4(this.invMatrix).clamp(this.min, this.max).applyMatrix4(this.matrix);
		return target1;
	};
})();
OrientedBox.prototype.distanceToPoint = (function() {
	const target = new Vector3();
	return function distanceToPoint(point) {
		this.closestPointToPoint(point, target);
		return point.distanceTo(target);
	};
})();
OrientedBox.prototype.distanceToBox = (function() {
	const xyzFields = [
		"x",
		"y",
		"z"
	];
	const segments1 = new Array(12).fill().map(() => new Line3());
	const segments2 = new Array(12).fill().map(() => new Line3());
	const point1 = new Vector3();
	const point2 = new Vector3();
	return function distanceToBox(box, threshold = 0, target1 = null, target2 = null) {
		if (this.needsUpdate) this.update();
		if (this.intersectsBox(box)) {
			if (target1 || target2) {
				box.getCenter(point2);
				this.closestPointToPoint(point2, point1);
				box.closestPointToPoint(point1, point2);
				if (target1) target1.copy(point1);
				if (target2) target2.copy(point2);
			}
			return 0;
		}
		const threshold2 = threshold * threshold;
		const min = box.min;
		const max = box.max;
		const points = this.points;
		let closestDistanceSq = Infinity;
		for (let i = 0; i < 8; i++) {
			const p = points[i];
			point2.copy(p).clamp(min, max);
			const dist = p.distanceToSquared(point2);
			if (dist < closestDistanceSq) {
				closestDistanceSq = dist;
				if (target1) target1.copy(p);
				if (target2) target2.copy(point2);
				if (dist < threshold2) return Math.sqrt(dist);
			}
		}
		let count = 0;
		for (let i = 0; i < 3; i++) for (let i1 = 0; i1 <= 1; i1++) for (let i2 = 0; i2 <= 1; i2++) {
			const nextIndex = (i + 1) % 3;
			const nextIndex2 = (i + 2) % 3;
			const index = i1 << nextIndex | i2 << nextIndex2;
			const index2 = 1 << i | i1 << nextIndex | i2 << nextIndex2;
			const p1 = points[index];
			const p2 = points[index2];
			segments1[count].set(p1, p2);
			const f1 = xyzFields[i];
			const f2 = xyzFields[nextIndex];
			const f3 = xyzFields[nextIndex2];
			const line2 = segments2[count];
			const start = line2.start;
			const end = line2.end;
			start[f1] = min[f1];
			start[f2] = i1 ? min[f2] : max[f2];
			start[f3] = i2 ? min[f3] : max[f2];
			end[f1] = max[f1];
			end[f2] = i1 ? min[f2] : max[f2];
			end[f3] = i2 ? min[f3] : max[f2];
			count++;
		}
		for (let x = 0; x <= 1; x++) for (let y = 0; y <= 1; y++) for (let z = 0; z <= 1; z++) {
			point2.x = x ? max.x : min.x;
			point2.y = y ? max.y : min.y;
			point2.z = z ? max.z : min.z;
			this.closestPointToPoint(point2, point1);
			const dist = point2.distanceToSquared(point1);
			if (dist < closestDistanceSq) {
				closestDistanceSq = dist;
				if (target1) target1.copy(point1);
				if (target2) target2.copy(point2);
				if (dist < threshold2) return Math.sqrt(dist);
			}
		}
		for (let i = 0; i < 12; i++) {
			const l1 = segments1[i];
			for (let i2 = 0; i2 < 12; i2++) {
				const l2 = segments2[i2];
				closestPointsSegmentToSegment(l1, l2, point1, point2);
				const dist = point1.distanceToSquared(point2);
				if (dist < closestDistanceSq) {
					closestDistanceSq = dist;
					if (target1) target1.copy(point1);
					if (target2) target2.copy(point2);
					if (dist < threshold2) return Math.sqrt(dist);
				}
			}
		}
		return Math.sqrt(closestDistanceSq);
	};
})();
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/PrimitivePool.js
var PrimitivePool = class {
	constructor(getNewPrimitive) {
		this._getNewPrimitive = getNewPrimitive;
		this._primitives = [];
	}
	getPrimitive() {
		const primitives = this._primitives;
		if (primitives.length === 0) return this._getNewPrimitive();
		else return primitives.pop();
	}
	releasePrimitive(primitive) {
		this._primitives.push(primitive);
	}
};
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/ExtendedTrianglePool.js
var ExtendedTrianglePoolBase = class extends PrimitivePool {
	constructor() {
		super(() => new ExtendedTriangle());
	}
};
var ExtendedTrianglePool = /* @__PURE__ */ new ExtendedTrianglePoolBase();
//#endregion
//#region node_modules/three-mesh-bvh/src/core/utils/BufferStack.js
var _BufferStack = class {
	constructor() {
		this.float32Array = null;
		this.uint16Array = null;
		this.uint32Array = null;
		const stack = [];
		let prevBuffer = null;
		this.setBuffer = (buffer) => {
			if (prevBuffer) stack.push(prevBuffer);
			prevBuffer = buffer;
			this.float32Array = new Float32Array(buffer);
			this.uint16Array = new Uint16Array(buffer);
			this.uint32Array = new Uint32Array(buffer);
		};
		this.clearBuffer = () => {
			prevBuffer = null;
			this.float32Array = null;
			this.uint16Array = null;
			this.uint32Array = null;
			if (stack.length !== 0) this.setBuffer(stack.pop());
		};
	}
};
var BufferStack = new _BufferStack();
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/shapecast.js
var _box1, _box2;
var boxStack = [];
var boxPool = /* @__PURE__ */ new PrimitivePool(() => new Box3());
function shapecast(bvh, root, intersectsBounds, intersectsRange, boundsTraverseOrder, byteOffset) {
	_box1 = boxPool.getPrimitive();
	_box2 = boxPool.getPrimitive();
	boxStack.push(_box1, _box2);
	BufferStack.setBuffer(bvh._roots[root]);
	const result = shapecastTraverse(0, bvh.geometry, intersectsBounds, intersectsRange, boundsTraverseOrder, byteOffset);
	BufferStack.clearBuffer();
	boxPool.releasePrimitive(_box1);
	boxPool.releasePrimitive(_box2);
	boxStack.pop();
	boxStack.pop();
	const length = boxStack.length;
	if (length > 0) {
		_box2 = boxStack[length - 1];
		_box1 = boxStack[length - 2];
	}
	return result;
}
function shapecastTraverse(nodeIndex32, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc = null, nodeIndexByteOffset = 0, depth = 0) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	let nodeIndex16 = nodeIndex32 * 2;
	if (IS_LEAF(nodeIndex16, uint16Array)) {
		const offset = OFFSET(nodeIndex32, uint32Array);
		const count = COUNT(nodeIndex16, uint16Array);
		arrayToBox(BOUNDING_DATA_INDEX(nodeIndex32), float32Array, _box1);
		return intersectsRangeFunc(offset, count, false, depth, nodeIndexByteOffset + nodeIndex32, _box1);
	} else {
		const left = LEFT_NODE(nodeIndex32);
		const right = RIGHT_NODE(nodeIndex32, uint32Array);
		let c1 = left;
		let c2 = right;
		let score1, score2;
		let box1, box2;
		if (nodeScoreFunc) {
			box1 = _box1;
			box2 = _box2;
			arrayToBox(BOUNDING_DATA_INDEX(c1), float32Array, box1);
			arrayToBox(BOUNDING_DATA_INDEX(c2), float32Array, box2);
			score1 = nodeScoreFunc(box1);
			score2 = nodeScoreFunc(box2);
			if (score2 < score1) {
				c1 = right;
				c2 = left;
				const temp = score1;
				score1 = score2;
				score2 = temp;
				box1 = box2;
			}
		}
		if (!box1) {
			box1 = _box1;
			arrayToBox(BOUNDING_DATA_INDEX(c1), float32Array, box1);
		}
		const isC1Leaf = IS_LEAF(c1 * 2, uint16Array);
		const c1Intersection = intersectsBoundsFunc(box1, isC1Leaf, score1, depth + 1, nodeIndexByteOffset + c1);
		let c1StopTraversal;
		if (c1Intersection === 2) {
			const offset = getLeftOffset(c1);
			c1StopTraversal = intersectsRangeFunc(offset, getRightEndOffset(c1) - offset, true, depth + 1, nodeIndexByteOffset + c1, box1);
		} else c1StopTraversal = c1Intersection && shapecastTraverse(c1, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc, nodeIndexByteOffset, depth + 1);
		if (c1StopTraversal) return true;
		box2 = _box2;
		arrayToBox(BOUNDING_DATA_INDEX(c2), float32Array, box2);
		const isC2Leaf = IS_LEAF(c2 * 2, uint16Array);
		const c2Intersection = intersectsBoundsFunc(box2, isC2Leaf, score2, depth + 1, nodeIndexByteOffset + c2);
		let c2StopTraversal;
		if (c2Intersection === 2) {
			const offset = getLeftOffset(c2);
			c2StopTraversal = intersectsRangeFunc(offset, getRightEndOffset(c2) - offset, true, depth + 1, nodeIndexByteOffset + c2, box2);
		} else c2StopTraversal = c2Intersection && shapecastTraverse(c2, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc, nodeIndexByteOffset, depth + 1);
		if (c2StopTraversal) return true;
		return false;
		function getLeftOffset(nodeIndex32) {
			const { uint16Array, uint32Array } = BufferStack;
			let nodeIndex16 = nodeIndex32 * 2;
			while (!IS_LEAF(nodeIndex16, uint16Array)) {
				nodeIndex32 = LEFT_NODE(nodeIndex32);
				nodeIndex16 = nodeIndex32 * 2;
			}
			return OFFSET(nodeIndex32, uint32Array);
		}
		function getRightEndOffset(nodeIndex32) {
			const { uint16Array, uint32Array } = BufferStack;
			let nodeIndex16 = nodeIndex32 * 2;
			while (!IS_LEAF(nodeIndex16, uint16Array)) {
				nodeIndex32 = RIGHT_NODE(nodeIndex32, uint32Array);
				nodeIndex16 = nodeIndex32 * 2;
			}
			return OFFSET(nodeIndex32, uint32Array) + COUNT(nodeIndex16, uint16Array);
		}
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/closestPointToPoint.js
var temp = /* @__PURE__ */ new Vector3();
var temp1$2 = /* @__PURE__ */ new Vector3();
function closestPointToPoint(bvh, point, target = {}, minThreshold = 0, maxThreshold = Infinity) {
	const minThresholdSq = minThreshold * minThreshold;
	const maxThresholdSq = maxThreshold * maxThreshold;
	let closestDistanceSq = Infinity;
	let closestDistanceTriIndex = null;
	bvh.shapecast({
		boundsTraverseOrder: (box) => {
			temp.copy(point).clamp(box.min, box.max);
			return temp.distanceToSquared(point);
		},
		intersectsBounds: (box, isLeaf, score) => {
			return score < closestDistanceSq && score < maxThresholdSq;
		},
		intersectsTriangle: (tri, triIndex) => {
			tri.closestPointToPoint(point, temp);
			const distSq = point.distanceToSquared(temp);
			if (distSq < closestDistanceSq) {
				temp1$2.copy(temp);
				closestDistanceSq = distSq;
				closestDistanceTriIndex = triIndex;
			}
			if (distSq < minThresholdSq) return true;
			else return false;
		}
	});
	if (closestDistanceSq === Infinity) return null;
	const closestDistance = Math.sqrt(closestDistanceSq);
	if (!target.point) target.point = temp1$2.clone();
	else target.point.copy(temp1$2);
	target.distance = closestDistance, target.faceIndex = closestDistanceTriIndex;
	return target;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/ThreeRayIntersectUtilities.js
var IS_GT_REVISION_169 = parseInt("184") >= 169;
var _vA$1 = /* @__PURE__ */ new Vector3();
var _vB = /* @__PURE__ */ new Vector3();
var _vC = /* @__PURE__ */ new Vector3();
var _uvA = /* @__PURE__ */ new Vector2();
var _uvB = /* @__PURE__ */ new Vector2();
var _uvC = /* @__PURE__ */ new Vector2();
var _normalA = /* @__PURE__ */ new Vector3();
var _normalB = /* @__PURE__ */ new Vector3();
var _normalC = /* @__PURE__ */ new Vector3();
var _intersectionPoint = /* @__PURE__ */ new Vector3();
function checkIntersection(ray, pA, pB, pC, point, side, near, far) {
	let intersect;
	if (side === 1) intersect = ray.intersectTriangle(pC, pB, pA, true, point);
	else intersect = ray.intersectTriangle(pA, pB, pC, side !== 2, point);
	if (intersect === null) return null;
	const distance = ray.origin.distanceTo(point);
	if (distance < near || distance > far) return null;
	return {
		distance,
		point: point.clone()
	};
}
function checkBufferGeometryIntersection(ray, position, normal, uv, uv1, a, b, c, side, near, far) {
	_vA$1.fromBufferAttribute(position, a);
	_vB.fromBufferAttribute(position, b);
	_vC.fromBufferAttribute(position, c);
	const intersection = checkIntersection(ray, _vA$1, _vB, _vC, _intersectionPoint, side, near, far);
	if (intersection) {
		const barycoord = new Vector3();
		Triangle.getBarycoord(_intersectionPoint, _vA$1, _vB, _vC, barycoord);
		if (uv) {
			_uvA.fromBufferAttribute(uv, a);
			_uvB.fromBufferAttribute(uv, b);
			_uvC.fromBufferAttribute(uv, c);
			intersection.uv = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB, _vC, _uvA, _uvB, _uvC, new Vector2());
		}
		if (uv1) {
			_uvA.fromBufferAttribute(uv1, a);
			_uvB.fromBufferAttribute(uv1, b);
			_uvC.fromBufferAttribute(uv1, c);
			intersection.uv1 = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB, _vC, _uvA, _uvB, _uvC, new Vector2());
		}
		if (normal) {
			_normalA.fromBufferAttribute(normal, a);
			_normalB.fromBufferAttribute(normal, b);
			_normalC.fromBufferAttribute(normal, c);
			intersection.normal = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB, _vC, _normalA, _normalB, _normalC, new Vector3());
			if (intersection.normal.dot(ray.direction) > 0) intersection.normal.multiplyScalar(-1);
		}
		const face = {
			a,
			b,
			c,
			normal: new Vector3(),
			materialIndex: 0
		};
		Triangle.getNormal(_vA$1, _vB, _vC, face.normal);
		intersection.face = face;
		intersection.faceIndex = a;
		if (IS_GT_REVISION_169) intersection.barycoord = barycoord;
	}
	return intersection;
}
function intersectTri(geo, side, ray, tri, intersections, near, far) {
	const triOffset = tri * 3;
	let a = triOffset + 0;
	let b = triOffset + 1;
	let c = triOffset + 2;
	const index = geo.index;
	if (geo.index) {
		a = index.getX(a);
		b = index.getX(b);
		c = index.getX(c);
	}
	const { position, normal, uv, uv1 } = geo.attributes;
	const intersection = checkBufferGeometryIntersection(ray, position, normal, uv, uv1, a, b, c, side, near, far);
	if (intersection) {
		intersection.faceIndex = tri;
		if (intersections) intersections.push(intersection);
		return intersection;
	}
	return null;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/TriangleUtilities.js
function setTriangle(tri, i, index, pos) {
	const ta = tri.a;
	const tb = tri.b;
	const tc = tri.c;
	let i0 = i;
	let i1 = i + 1;
	let i2 = i + 2;
	if (index) {
		i0 = index.getX(i0);
		i1 = index.getX(i1);
		i2 = index.getX(i2);
	}
	ta.x = pos.getX(i0);
	ta.y = pos.getY(i0);
	ta.z = pos.getZ(i0);
	tb.x = pos.getX(i1);
	tb.y = pos.getY(i1);
	tb.z = pos.getZ(i1);
	tc.x = pos.getX(i2);
	tc.y = pos.getY(i2);
	tc.z = pos.getZ(i2);
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/utils/iterationUtils.generated.js
function intersectTris(bvh, side, ray, offset, count, intersections, near, far) {
	const { geometry, _indirectBuffer } = bvh;
	for (let i = offset, end = offset + count; i < end; i++) intersectTri(geometry, side, ray, i, intersections, near, far);
}
function intersectClosestTri(bvh, side, ray, offset, count, near, far) {
	const { geometry, _indirectBuffer } = bvh;
	let dist = Infinity;
	let res = null;
	for (let i = offset, end = offset + count; i < end; i++) {
		let intersection;
		intersection = intersectTri(geometry, side, ray, i, null, near, far);
		if (intersection && intersection.distance < dist) {
			res = intersection;
			dist = intersection.distance;
		}
	}
	return res;
}
function iterateOverTriangles(offset, count, bvh, intersectsTriangleFunc, contained, depth, triangle) {
	const { geometry } = bvh;
	const { index } = geometry;
	const pos = geometry.attributes.position;
	for (let i = offset, l = count + offset; i < l; i++) {
		let tri;
		tri = i;
		setTriangle(triangle, tri * 3, index, pos);
		triangle.needsUpdate = true;
		if (intersectsTriangleFunc(triangle, tri, contained, depth)) return true;
	}
	return false;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/refit.generated.js
function refit(bvh, nodeIndices = null) {
	if (nodeIndices && Array.isArray(nodeIndices)) nodeIndices = new Set(nodeIndices);
	const geometry = bvh.geometry;
	const indexArr = geometry.index ? geometry.index.array : null;
	const posAttr = geometry.attributes.position;
	let buffer, uint32Array, uint16Array, float32Array;
	let byteOffset = 0;
	const roots = bvh._roots;
	for (let i = 0, l = roots.length; i < l; i++) {
		buffer = roots[i];
		uint32Array = new Uint32Array(buffer);
		uint16Array = new Uint16Array(buffer);
		float32Array = new Float32Array(buffer);
		_traverse(0, byteOffset);
		byteOffset += buffer.byteLength;
	}
	function _traverse(node32Index, byteOffset, force = false) {
		const node16Index = node32Index * 2;
		if (uint16Array[node16Index + 15] === 65535) {
			const offset = uint32Array[node32Index + 6];
			const count = uint16Array[node16Index + 14];
			let minx = Infinity;
			let miny = Infinity;
			let minz = Infinity;
			let maxx = -Infinity;
			let maxy = -Infinity;
			let maxz = -Infinity;
			for (let i = 3 * offset, l = 3 * (offset + count); i < l; i++) {
				let index = indexArr[i];
				const x = posAttr.getX(index);
				const y = posAttr.getY(index);
				const z = posAttr.getZ(index);
				if (x < minx) minx = x;
				if (x > maxx) maxx = x;
				if (y < miny) miny = y;
				if (y > maxy) maxy = y;
				if (z < minz) minz = z;
				if (z > maxz) maxz = z;
			}
			if (float32Array[node32Index + 0] !== minx || float32Array[node32Index + 1] !== miny || float32Array[node32Index + 2] !== minz || float32Array[node32Index + 3] !== maxx || float32Array[node32Index + 4] !== maxy || float32Array[node32Index + 5] !== maxz) {
				float32Array[node32Index + 0] = minx;
				float32Array[node32Index + 1] = miny;
				float32Array[node32Index + 2] = minz;
				float32Array[node32Index + 3] = maxx;
				float32Array[node32Index + 4] = maxy;
				float32Array[node32Index + 5] = maxz;
				return true;
			} else return false;
		} else {
			const left = node32Index + 8;
			const right = uint32Array[node32Index + 6];
			const offsetLeft = left + byteOffset;
			const offsetRight = right + byteOffset;
			let forceChildren = force;
			let includesLeft = false;
			let includesRight = false;
			if (nodeIndices) {
				if (!forceChildren) {
					includesLeft = nodeIndices.has(offsetLeft);
					includesRight = nodeIndices.has(offsetRight);
					forceChildren = !includesLeft && !includesRight;
				}
			} else {
				includesLeft = true;
				includesRight = true;
			}
			const traverseLeft = forceChildren || includesLeft;
			const traverseRight = forceChildren || includesRight;
			let leftChange = false;
			if (traverseLeft) leftChange = _traverse(left, byteOffset, forceChildren);
			let rightChange = false;
			if (traverseRight) rightChange = _traverse(right, byteOffset, forceChildren);
			const didChange = leftChange || rightChange;
			if (didChange) for (let i = 0; i < 3; i++) {
				const lefti = left + i;
				const righti = right + i;
				const minLeftValue = float32Array[lefti];
				const maxLeftValue = float32Array[lefti + 3];
				const minRightValue = float32Array[righti];
				const maxRightValue = float32Array[righti + 3];
				float32Array[node32Index + i] = minLeftValue < minRightValue ? minLeftValue : minRightValue;
				float32Array[node32Index + i + 3] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;
			}
			return didChange;
		}
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/utils/intersectUtils.js
/**
* This function performs intersection tests similar to Ray.intersectBox in three.js,
* with the difference that the box values are read from an array to improve performance.
*/
function intersectRay(nodeIndex32, array, ray, near, far) {
	let tmin, tmax, tymin, tymax, tzmin, tzmax;
	const invdirx = 1 / ray.direction.x, invdiry = 1 / ray.direction.y, invdirz = 1 / ray.direction.z;
	const ox = ray.origin.x;
	const oy = ray.origin.y;
	const oz = ray.origin.z;
	let minx = array[nodeIndex32];
	let maxx = array[nodeIndex32 + 3];
	let miny = array[nodeIndex32 + 1];
	let maxy = array[nodeIndex32 + 3 + 1];
	let minz = array[nodeIndex32 + 2];
	let maxz = array[nodeIndex32 + 3 + 2];
	if (invdirx >= 0) {
		tmin = (minx - ox) * invdirx;
		tmax = (maxx - ox) * invdirx;
	} else {
		tmin = (maxx - ox) * invdirx;
		tmax = (minx - ox) * invdirx;
	}
	if (invdiry >= 0) {
		tymin = (miny - oy) * invdiry;
		tymax = (maxy - oy) * invdiry;
	} else {
		tymin = (maxy - oy) * invdiry;
		tymax = (miny - oy) * invdiry;
	}
	if (tmin > tymax || tymin > tmax) return false;
	if (tymin > tmin || isNaN(tmin)) tmin = tymin;
	if (tymax < tmax || isNaN(tmax)) tmax = tymax;
	if (invdirz >= 0) {
		tzmin = (minz - oz) * invdirz;
		tzmax = (maxz - oz) * invdirz;
	} else {
		tzmin = (maxz - oz) * invdirz;
		tzmax = (minz - oz) * invdirz;
	}
	if (tmin > tzmax || tzmin > tmax) return false;
	if (tzmin > tmin || tmin !== tmin) tmin = tzmin;
	if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
	return tmin <= far && tmax >= near;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/utils/iterationUtils_indirect.generated.js
function intersectTris_indirect(bvh, side, ray, offset, count, intersections, near, far) {
	const { geometry, _indirectBuffer } = bvh;
	for (let i = offset, end = offset + count; i < end; i++) intersectTri(geometry, side, ray, _indirectBuffer ? _indirectBuffer[i] : i, intersections, near, far);
}
function intersectClosestTri_indirect(bvh, side, ray, offset, count, near, far) {
	const { geometry, _indirectBuffer } = bvh;
	let dist = Infinity;
	let res = null;
	for (let i = offset, end = offset + count; i < end; i++) {
		let intersection;
		intersection = intersectTri(geometry, side, ray, _indirectBuffer ? _indirectBuffer[i] : i, null, near, far);
		if (intersection && intersection.distance < dist) {
			res = intersection;
			dist = intersection.distance;
		}
	}
	return res;
}
function iterateOverTriangles_indirect(offset, count, bvh, intersectsTriangleFunc, contained, depth, triangle) {
	const { geometry } = bvh;
	const { index } = geometry;
	const pos = geometry.attributes.position;
	for (let i = offset, l = count + offset; i < l; i++) {
		let tri;
		tri = bvh.resolveTriangleIndex(i);
		setTriangle(triangle, tri * 3, index, pos);
		triangle.needsUpdate = true;
		if (intersectsTriangleFunc(triangle, tri, contained, depth)) return true;
	}
	return false;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/raycast.generated.js
function raycast(bvh, root, side, ray, intersects, near, far) {
	BufferStack.setBuffer(bvh._roots[root]);
	_raycast$1(0, bvh, side, ray, intersects, near, far);
	BufferStack.clearBuffer();
}
function _raycast$1(nodeIndex32, bvh, side, ray, intersects, near, far) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	const nodeIndex16 = nodeIndex32 * 2;
	if (IS_LEAF(nodeIndex16, uint16Array)) intersectTris(bvh, side, ray, OFFSET(nodeIndex32, uint32Array), COUNT(nodeIndex16, uint16Array), intersects, near, far);
	else {
		const leftIndex = LEFT_NODE(nodeIndex32);
		if (intersectRay(leftIndex, float32Array, ray, near, far)) _raycast$1(leftIndex, bvh, side, ray, intersects, near, far);
		const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array);
		if (intersectRay(rightIndex, float32Array, ray, near, far)) _raycast$1(rightIndex, bvh, side, ray, intersects, near, far);
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/raycastFirst.generated.js
var _xyzFields$1 = [
	"x",
	"y",
	"z"
];
function raycastFirst(bvh, root, side, ray, near, far) {
	BufferStack.setBuffer(bvh._roots[root]);
	const result = _raycastFirst$1(0, bvh, side, ray, near, far);
	BufferStack.clearBuffer();
	return result;
}
function _raycastFirst$1(nodeIndex32, bvh, side, ray, near, far) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	let nodeIndex16 = nodeIndex32 * 2;
	if (IS_LEAF(nodeIndex16, uint16Array)) return intersectClosestTri(bvh, side, ray, OFFSET(nodeIndex32, uint32Array), COUNT(nodeIndex16, uint16Array), near, far);
	else {
		const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array);
		const xyzAxis = _xyzFields$1[splitAxis];
		const leftToRight = ray.direction[xyzAxis] >= 0;
		let c1, c2;
		if (leftToRight) {
			c1 = LEFT_NODE(nodeIndex32);
			c2 = RIGHT_NODE(nodeIndex32, uint32Array);
		} else {
			c1 = RIGHT_NODE(nodeIndex32, uint32Array);
			c2 = LEFT_NODE(nodeIndex32);
		}
		const c1Result = intersectRay(c1, float32Array, ray, near, far) ? _raycastFirst$1(c1, bvh, side, ray, near, far) : null;
		if (c1Result) {
			const point = c1Result.point[xyzAxis];
			if (leftToRight ? point <= float32Array[c2 + splitAxis] : point >= float32Array[c2 + splitAxis + 3]) return c1Result;
		}
		const c2Result = intersectRay(c2, float32Array, ray, near, far) ? _raycastFirst$1(c2, bvh, side, ray, near, far) : null;
		if (c1Result && c2Result) return c1Result.distance <= c2Result.distance ? c1Result : c2Result;
		else return c1Result || c2Result || null;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/intersectsGeometry.generated.js
var boundingBox$2 = /* @__PURE__ */ new Box3();
var triangle$1 = /* @__PURE__ */ new ExtendedTriangle();
var triangle2$1 = /* @__PURE__ */ new ExtendedTriangle();
var invertedMat$1 = /* @__PURE__ */ new Matrix4();
var obb$4 = /* @__PURE__ */ new OrientedBox();
var obb2$3 = /* @__PURE__ */ new OrientedBox();
function intersectsGeometry(bvh, root, otherGeometry, geometryToBvh) {
	BufferStack.setBuffer(bvh._roots[root]);
	const result = _intersectsGeometry$1(0, bvh, otherGeometry, geometryToBvh);
	BufferStack.clearBuffer();
	return result;
}
function _intersectsGeometry$1(nodeIndex32, bvh, otherGeometry, geometryToBvh, cachedObb = null) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	let nodeIndex16 = nodeIndex32 * 2;
	if (cachedObb === null) {
		if (!otherGeometry.boundingBox) otherGeometry.computeBoundingBox();
		obb$4.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh);
		cachedObb = obb$4;
	}
	if (IS_LEAF(nodeIndex16, uint16Array)) {
		const thisGeometry = bvh.geometry;
		const thisIndex = thisGeometry.index;
		const thisPos = thisGeometry.attributes.position;
		const index = otherGeometry.index;
		const pos = otherGeometry.attributes.position;
		const offset = OFFSET(nodeIndex32, uint32Array);
		const count = COUNT(nodeIndex16, uint16Array);
		invertedMat$1.copy(geometryToBvh).invert();
		if (otherGeometry.boundsTree) {
			arrayToBox(BOUNDING_DATA_INDEX(nodeIndex32), float32Array, obb2$3);
			obb2$3.matrix.copy(invertedMat$1);
			obb2$3.needsUpdate = true;
			return otherGeometry.boundsTree.shapecast({
				intersectsBounds: (box) => obb2$3.intersectsBox(box),
				intersectsTriangle: (tri) => {
					tri.a.applyMatrix4(geometryToBvh);
					tri.b.applyMatrix4(geometryToBvh);
					tri.c.applyMatrix4(geometryToBvh);
					tri.needsUpdate = true;
					for (let i = offset * 3, l = (count + offset) * 3; i < l; i += 3) {
						setTriangle(triangle2$1, i, thisIndex, thisPos);
						triangle2$1.needsUpdate = true;
						if (tri.intersectsTriangle(triangle2$1)) return true;
					}
					return false;
				}
			});
		} else for (let i = offset * 3, l = (count + offset) * 3; i < l; i += 3) {
			setTriangle(triangle$1, i, thisIndex, thisPos);
			triangle$1.a.applyMatrix4(invertedMat$1);
			triangle$1.b.applyMatrix4(invertedMat$1);
			triangle$1.c.applyMatrix4(invertedMat$1);
			triangle$1.needsUpdate = true;
			for (let i2 = 0, l2 = index.count; i2 < l2; i2 += 3) {
				setTriangle(triangle2$1, i2, index, pos);
				triangle2$1.needsUpdate = true;
				if (triangle$1.intersectsTriangle(triangle2$1)) return true;
			}
		}
	} else {
		const left = nodeIndex32 + 8;
		const right = uint32Array[nodeIndex32 + 6];
		arrayToBox(BOUNDING_DATA_INDEX(left), float32Array, boundingBox$2);
		if (cachedObb.intersectsBox(boundingBox$2) && _intersectsGeometry$1(left, bvh, otherGeometry, geometryToBvh, cachedObb)) return true;
		arrayToBox(BOUNDING_DATA_INDEX(right), float32Array, boundingBox$2);
		if (cachedObb.intersectsBox(boundingBox$2) && _intersectsGeometry$1(right, bvh, otherGeometry, geometryToBvh, cachedObb)) return true;
		return false;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/closestPointToGeometry.generated.js
var tempMatrix$2 = /* @__PURE__ */ new Matrix4();
var obb$3 = /* @__PURE__ */ new OrientedBox();
var obb2$2 = /* @__PURE__ */ new OrientedBox();
var temp1$1 = /* @__PURE__ */ new Vector3();
var temp2$1 = /* @__PURE__ */ new Vector3();
var temp3$1 = /* @__PURE__ */ new Vector3();
var temp4$1 = /* @__PURE__ */ new Vector3();
function closestPointToGeometry(bvh, otherGeometry, geometryToBvh, target1 = {}, target2 = {}, minThreshold = 0, maxThreshold = Infinity) {
	if (!otherGeometry.boundingBox) otherGeometry.computeBoundingBox();
	obb$3.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh);
	obb$3.needsUpdate = true;
	const geometry = bvh.geometry;
	const pos = geometry.attributes.position;
	const index = geometry.index;
	const otherPos = otherGeometry.attributes.position;
	const otherIndex = otherGeometry.index;
	const triangle = ExtendedTrianglePool.getPrimitive();
	const triangle2 = ExtendedTrianglePool.getPrimitive();
	let tempTarget1 = temp1$1;
	let tempTargetDest1 = temp2$1;
	let tempTarget2 = null;
	let tempTargetDest2 = null;
	if (target2) {
		tempTarget2 = temp3$1;
		tempTargetDest2 = temp4$1;
	}
	let closestDistance = Infinity;
	let closestDistanceTriIndex = null;
	let closestDistanceOtherTriIndex = null;
	tempMatrix$2.copy(geometryToBvh).invert();
	obb2$2.matrix.copy(tempMatrix$2);
	bvh.shapecast({
		boundsTraverseOrder: (box) => {
			return obb$3.distanceToBox(box);
		},
		intersectsBounds: (box, isLeaf, score) => {
			if (score < closestDistance && score < maxThreshold) {
				if (isLeaf) {
					obb2$2.min.copy(box.min);
					obb2$2.max.copy(box.max);
					obb2$2.needsUpdate = true;
				}
				return true;
			}
			return false;
		},
		intersectsRange: (offset, count) => {
			if (otherGeometry.boundsTree) return otherGeometry.boundsTree.shapecast({
				boundsTraverseOrder: (box) => {
					return obb2$2.distanceToBox(box);
				},
				intersectsBounds: (box, isLeaf, score) => {
					return score < closestDistance && score < maxThreshold;
				},
				intersectsRange: (otherOffset, otherCount) => {
					for (let i2 = otherOffset, l2 = otherOffset + otherCount; i2 < l2; i2++) {
						setTriangle(triangle2, 3 * i2, otherIndex, otherPos);
						triangle2.a.applyMatrix4(geometryToBvh);
						triangle2.b.applyMatrix4(geometryToBvh);
						triangle2.c.applyMatrix4(geometryToBvh);
						triangle2.needsUpdate = true;
						for (let i = offset, l = offset + count; i < l; i++) {
							setTriangle(triangle, 3 * i, index, pos);
							triangle.needsUpdate = true;
							const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2);
							if (dist < closestDistance) {
								tempTargetDest1.copy(tempTarget1);
								if (tempTargetDest2) tempTargetDest2.copy(tempTarget2);
								closestDistance = dist;
								closestDistanceTriIndex = i;
								closestDistanceOtherTriIndex = i2;
							}
							if (dist < minThreshold) return true;
						}
					}
				}
			});
			else {
				const triCount = getTriCount(otherGeometry);
				for (let i2 = 0, l2 = triCount; i2 < l2; i2++) {
					setTriangle(triangle2, 3 * i2, otherIndex, otherPos);
					triangle2.a.applyMatrix4(geometryToBvh);
					triangle2.b.applyMatrix4(geometryToBvh);
					triangle2.c.applyMatrix4(geometryToBvh);
					triangle2.needsUpdate = true;
					for (let i = offset, l = offset + count; i < l; i++) {
						setTriangle(triangle, 3 * i, index, pos);
						triangle.needsUpdate = true;
						const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2);
						if (dist < closestDistance) {
							tempTargetDest1.copy(tempTarget1);
							if (tempTargetDest2) tempTargetDest2.copy(tempTarget2);
							closestDistance = dist;
							closestDistanceTriIndex = i;
							closestDistanceOtherTriIndex = i2;
						}
						if (dist < minThreshold) return true;
					}
				}
			}
		}
	});
	ExtendedTrianglePool.releasePrimitive(triangle);
	ExtendedTrianglePool.releasePrimitive(triangle2);
	if (closestDistance === Infinity) return null;
	if (!target1.point) target1.point = tempTargetDest1.clone();
	else target1.point.copy(tempTargetDest1);
	target1.distance = closestDistance, target1.faceIndex = closestDistanceTriIndex;
	if (target2) {
		if (!target2.point) target2.point = tempTargetDest2.clone();
		else target2.point.copy(tempTargetDest2);
		target2.point.applyMatrix4(tempMatrix$2);
		tempTargetDest1.applyMatrix4(tempMatrix$2);
		target2.distance = tempTargetDest1.sub(target2.point).length();
		target2.faceIndex = closestDistanceOtherTriIndex;
	}
	return target1;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/refit_indirect.generated.js
function refit_indirect(bvh, nodeIndices = null) {
	if (nodeIndices && Array.isArray(nodeIndices)) nodeIndices = new Set(nodeIndices);
	const geometry = bvh.geometry;
	const indexArr = geometry.index ? geometry.index.array : null;
	const posAttr = geometry.attributes.position;
	let buffer, uint32Array, uint16Array, float32Array;
	let byteOffset = 0;
	const roots = bvh._roots;
	for (let i = 0, l = roots.length; i < l; i++) {
		buffer = roots[i];
		uint32Array = new Uint32Array(buffer);
		uint16Array = new Uint16Array(buffer);
		float32Array = new Float32Array(buffer);
		_traverse(0, byteOffset);
		byteOffset += buffer.byteLength;
	}
	function _traverse(node32Index, byteOffset, force = false) {
		const node16Index = node32Index * 2;
		if (uint16Array[node16Index + 15] === 65535) {
			const offset = uint32Array[node32Index + 6];
			const count = uint16Array[node16Index + 14];
			let minx = Infinity;
			let miny = Infinity;
			let minz = Infinity;
			let maxx = -Infinity;
			let maxy = -Infinity;
			let maxz = -Infinity;
			for (let i = offset, l = offset + count; i < l; i++) {
				const t = 3 * bvh.resolveTriangleIndex(i);
				for (let j = 0; j < 3; j++) {
					let index = t + j;
					index = indexArr ? indexArr[index] : index;
					const x = posAttr.getX(index);
					const y = posAttr.getY(index);
					const z = posAttr.getZ(index);
					if (x < minx) minx = x;
					if (x > maxx) maxx = x;
					if (y < miny) miny = y;
					if (y > maxy) maxy = y;
					if (z < minz) minz = z;
					if (z > maxz) maxz = z;
				}
			}
			if (float32Array[node32Index + 0] !== minx || float32Array[node32Index + 1] !== miny || float32Array[node32Index + 2] !== minz || float32Array[node32Index + 3] !== maxx || float32Array[node32Index + 4] !== maxy || float32Array[node32Index + 5] !== maxz) {
				float32Array[node32Index + 0] = minx;
				float32Array[node32Index + 1] = miny;
				float32Array[node32Index + 2] = minz;
				float32Array[node32Index + 3] = maxx;
				float32Array[node32Index + 4] = maxy;
				float32Array[node32Index + 5] = maxz;
				return true;
			} else return false;
		} else {
			const left = node32Index + 8;
			const right = uint32Array[node32Index + 6];
			const offsetLeft = left + byteOffset;
			const offsetRight = right + byteOffset;
			let forceChildren = force;
			let includesLeft = false;
			let includesRight = false;
			if (nodeIndices) {
				if (!forceChildren) {
					includesLeft = nodeIndices.has(offsetLeft);
					includesRight = nodeIndices.has(offsetRight);
					forceChildren = !includesLeft && !includesRight;
				}
			} else {
				includesLeft = true;
				includesRight = true;
			}
			const traverseLeft = forceChildren || includesLeft;
			const traverseRight = forceChildren || includesRight;
			let leftChange = false;
			if (traverseLeft) leftChange = _traverse(left, byteOffset, forceChildren);
			let rightChange = false;
			if (traverseRight) rightChange = _traverse(right, byteOffset, forceChildren);
			const didChange = leftChange || rightChange;
			if (didChange) for (let i = 0; i < 3; i++) {
				const lefti = left + i;
				const righti = right + i;
				const minLeftValue = float32Array[lefti];
				const maxLeftValue = float32Array[lefti + 3];
				const minRightValue = float32Array[righti];
				const maxRightValue = float32Array[righti + 3];
				float32Array[node32Index + i] = minLeftValue < minRightValue ? minLeftValue : minRightValue;
				float32Array[node32Index + i + 3] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;
			}
			return didChange;
		}
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/raycast_indirect.generated.js
function raycast_indirect(bvh, root, side, ray, intersects, near, far) {
	BufferStack.setBuffer(bvh._roots[root]);
	_raycast(0, bvh, side, ray, intersects, near, far);
	BufferStack.clearBuffer();
}
function _raycast(nodeIndex32, bvh, side, ray, intersects, near, far) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	const nodeIndex16 = nodeIndex32 * 2;
	if (IS_LEAF(nodeIndex16, uint16Array)) intersectTris_indirect(bvh, side, ray, OFFSET(nodeIndex32, uint32Array), COUNT(nodeIndex16, uint16Array), intersects, near, far);
	else {
		const leftIndex = LEFT_NODE(nodeIndex32);
		if (intersectRay(leftIndex, float32Array, ray, near, far)) _raycast(leftIndex, bvh, side, ray, intersects, near, far);
		const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array);
		if (intersectRay(rightIndex, float32Array, ray, near, far)) _raycast(rightIndex, bvh, side, ray, intersects, near, far);
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/raycastFirst_indirect.generated.js
var _xyzFields = [
	"x",
	"y",
	"z"
];
function raycastFirst_indirect(bvh, root, side, ray, near, far) {
	BufferStack.setBuffer(bvh._roots[root]);
	const result = _raycastFirst(0, bvh, side, ray, near, far);
	BufferStack.clearBuffer();
	return result;
}
function _raycastFirst(nodeIndex32, bvh, side, ray, near, far) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	let nodeIndex16 = nodeIndex32 * 2;
	if (IS_LEAF(nodeIndex16, uint16Array)) return intersectClosestTri_indirect(bvh, side, ray, OFFSET(nodeIndex32, uint32Array), COUNT(nodeIndex16, uint16Array), near, far);
	else {
		const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array);
		const xyzAxis = _xyzFields[splitAxis];
		const leftToRight = ray.direction[xyzAxis] >= 0;
		let c1, c2;
		if (leftToRight) {
			c1 = LEFT_NODE(nodeIndex32);
			c2 = RIGHT_NODE(nodeIndex32, uint32Array);
		} else {
			c1 = RIGHT_NODE(nodeIndex32, uint32Array);
			c2 = LEFT_NODE(nodeIndex32);
		}
		const c1Result = intersectRay(c1, float32Array, ray, near, far) ? _raycastFirst(c1, bvh, side, ray, near, far) : null;
		if (c1Result) {
			const point = c1Result.point[xyzAxis];
			if (leftToRight ? point <= float32Array[c2 + splitAxis] : point >= float32Array[c2 + splitAxis + 3]) return c1Result;
		}
		const c2Result = intersectRay(c2, float32Array, ray, near, far) ? _raycastFirst(c2, bvh, side, ray, near, far) : null;
		if (c1Result && c2Result) return c1Result.distance <= c2Result.distance ? c1Result : c2Result;
		else return c1Result || c2Result || null;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/intersectsGeometry_indirect.generated.js
var boundingBox$1 = /* @__PURE__ */ new Box3();
var triangle = /* @__PURE__ */ new ExtendedTriangle();
var triangle2 = /* @__PURE__ */ new ExtendedTriangle();
var invertedMat = /* @__PURE__ */ new Matrix4();
var obb$2 = /* @__PURE__ */ new OrientedBox();
var obb2$1 = /* @__PURE__ */ new OrientedBox();
function intersectsGeometry_indirect(bvh, root, otherGeometry, geometryToBvh) {
	BufferStack.setBuffer(bvh._roots[root]);
	const result = _intersectsGeometry(0, bvh, otherGeometry, geometryToBvh);
	BufferStack.clearBuffer();
	return result;
}
function _intersectsGeometry(nodeIndex32, bvh, otherGeometry, geometryToBvh, cachedObb = null) {
	const { float32Array, uint16Array, uint32Array } = BufferStack;
	let nodeIndex16 = nodeIndex32 * 2;
	if (cachedObb === null) {
		if (!otherGeometry.boundingBox) otherGeometry.computeBoundingBox();
		obb$2.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh);
		cachedObb = obb$2;
	}
	if (IS_LEAF(nodeIndex16, uint16Array)) {
		const thisGeometry = bvh.geometry;
		const thisIndex = thisGeometry.index;
		const thisPos = thisGeometry.attributes.position;
		const index = otherGeometry.index;
		const pos = otherGeometry.attributes.position;
		const offset = OFFSET(nodeIndex32, uint32Array);
		const count = COUNT(nodeIndex16, uint16Array);
		invertedMat.copy(geometryToBvh).invert();
		if (otherGeometry.boundsTree) {
			arrayToBox(BOUNDING_DATA_INDEX(nodeIndex32), float32Array, obb2$1);
			obb2$1.matrix.copy(invertedMat);
			obb2$1.needsUpdate = true;
			return otherGeometry.boundsTree.shapecast({
				intersectsBounds: (box) => obb2$1.intersectsBox(box),
				intersectsTriangle: (tri) => {
					tri.a.applyMatrix4(geometryToBvh);
					tri.b.applyMatrix4(geometryToBvh);
					tri.c.applyMatrix4(geometryToBvh);
					tri.needsUpdate = true;
					for (let i = offset, l = count + offset; i < l; i++) {
						setTriangle(triangle2, 3 * bvh.resolveTriangleIndex(i), thisIndex, thisPos);
						triangle2.needsUpdate = true;
						if (tri.intersectsTriangle(triangle2)) return true;
					}
					return false;
				}
			});
		} else for (let i = offset, l = count + offset; i < l; i++) {
			setTriangle(triangle, 3 * bvh.resolveTriangleIndex(i), thisIndex, thisPos);
			triangle.a.applyMatrix4(invertedMat);
			triangle.b.applyMatrix4(invertedMat);
			triangle.c.applyMatrix4(invertedMat);
			triangle.needsUpdate = true;
			for (let i2 = 0, l2 = index.count; i2 < l2; i2 += 3) {
				setTriangle(triangle2, i2, index, pos);
				triangle2.needsUpdate = true;
				if (triangle.intersectsTriangle(triangle2)) return true;
			}
		}
	} else {
		const left = nodeIndex32 + 8;
		const right = uint32Array[nodeIndex32 + 6];
		arrayToBox(BOUNDING_DATA_INDEX(left), float32Array, boundingBox$1);
		if (cachedObb.intersectsBox(boundingBox$1) && _intersectsGeometry(left, bvh, otherGeometry, geometryToBvh, cachedObb)) return true;
		arrayToBox(BOUNDING_DATA_INDEX(right), float32Array, boundingBox$1);
		if (cachedObb.intersectsBox(boundingBox$1) && _intersectsGeometry(right, bvh, otherGeometry, geometryToBvh, cachedObb)) return true;
		return false;
	}
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/closestPointToGeometry_indirect.generated.js
var tempMatrix$1 = /* @__PURE__ */ new Matrix4();
var obb$1 = /* @__PURE__ */ new OrientedBox();
var obb2 = /* @__PURE__ */ new OrientedBox();
var temp1 = /* @__PURE__ */ new Vector3();
var temp2 = /* @__PURE__ */ new Vector3();
var temp3 = /* @__PURE__ */ new Vector3();
var temp4 = /* @__PURE__ */ new Vector3();
function closestPointToGeometry_indirect(bvh, otherGeometry, geometryToBvh, target1 = {}, target2 = {}, minThreshold = 0, maxThreshold = Infinity) {
	if (!otherGeometry.boundingBox) otherGeometry.computeBoundingBox();
	obb$1.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh);
	obb$1.needsUpdate = true;
	const geometry = bvh.geometry;
	const pos = geometry.attributes.position;
	const index = geometry.index;
	const otherPos = otherGeometry.attributes.position;
	const otherIndex = otherGeometry.index;
	const triangle = ExtendedTrianglePool.getPrimitive();
	const triangle2 = ExtendedTrianglePool.getPrimitive();
	let tempTarget1 = temp1;
	let tempTargetDest1 = temp2;
	let tempTarget2 = null;
	let tempTargetDest2 = null;
	if (target2) {
		tempTarget2 = temp3;
		tempTargetDest2 = temp4;
	}
	let closestDistance = Infinity;
	let closestDistanceTriIndex = null;
	let closestDistanceOtherTriIndex = null;
	tempMatrix$1.copy(geometryToBvh).invert();
	obb2.matrix.copy(tempMatrix$1);
	bvh.shapecast({
		boundsTraverseOrder: (box) => {
			return obb$1.distanceToBox(box);
		},
		intersectsBounds: (box, isLeaf, score) => {
			if (score < closestDistance && score < maxThreshold) {
				if (isLeaf) {
					obb2.min.copy(box.min);
					obb2.max.copy(box.max);
					obb2.needsUpdate = true;
				}
				return true;
			}
			return false;
		},
		intersectsRange: (offset, count) => {
			if (otherGeometry.boundsTree) {
				const otherBvh = otherGeometry.boundsTree;
				return otherBvh.shapecast({
					boundsTraverseOrder: (box) => {
						return obb2.distanceToBox(box);
					},
					intersectsBounds: (box, isLeaf, score) => {
						return score < closestDistance && score < maxThreshold;
					},
					intersectsRange: (otherOffset, otherCount) => {
						for (let i2 = otherOffset, l2 = otherOffset + otherCount; i2 < l2; i2++) {
							setTriangle(triangle2, 3 * otherBvh.resolveTriangleIndex(i2), otherIndex, otherPos);
							triangle2.a.applyMatrix4(geometryToBvh);
							triangle2.b.applyMatrix4(geometryToBvh);
							triangle2.c.applyMatrix4(geometryToBvh);
							triangle2.needsUpdate = true;
							for (let i = offset, l = offset + count; i < l; i++) {
								setTriangle(triangle, 3 * bvh.resolveTriangleIndex(i), index, pos);
								triangle.needsUpdate = true;
								const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2);
								if (dist < closestDistance) {
									tempTargetDest1.copy(tempTarget1);
									if (tempTargetDest2) tempTargetDest2.copy(tempTarget2);
									closestDistance = dist;
									closestDistanceTriIndex = i;
									closestDistanceOtherTriIndex = i2;
								}
								if (dist < minThreshold) return true;
							}
						}
					}
				});
			} else {
				const triCount = getTriCount(otherGeometry);
				for (let i2 = 0, l2 = triCount; i2 < l2; i2++) {
					setTriangle(triangle2, 3 * i2, otherIndex, otherPos);
					triangle2.a.applyMatrix4(geometryToBvh);
					triangle2.b.applyMatrix4(geometryToBvh);
					triangle2.c.applyMatrix4(geometryToBvh);
					triangle2.needsUpdate = true;
					for (let i = offset, l = offset + count; i < l; i++) {
						setTriangle(triangle, 3 * bvh.resolveTriangleIndex(i), index, pos);
						triangle.needsUpdate = true;
						const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2);
						if (dist < closestDistance) {
							tempTargetDest1.copy(tempTarget1);
							if (tempTargetDest2) tempTargetDest2.copy(tempTarget2);
							closestDistance = dist;
							closestDistanceTriIndex = i;
							closestDistanceOtherTriIndex = i2;
						}
						if (dist < minThreshold) return true;
					}
				}
			}
		}
	});
	ExtendedTrianglePool.releasePrimitive(triangle);
	ExtendedTrianglePool.releasePrimitive(triangle2);
	if (closestDistance === Infinity) return null;
	if (!target1.point) target1.point = tempTargetDest1.clone();
	else target1.point.copy(tempTargetDest1);
	target1.distance = closestDistance, target1.faceIndex = closestDistanceTriIndex;
	if (target2) {
		if (!target2.point) target2.point = tempTargetDest2.clone();
		else target2.point.copy(tempTargetDest2);
		target2.point.applyMatrix4(tempMatrix$1);
		tempTargetDest1.applyMatrix4(tempMatrix$1);
		target2.distance = tempTargetDest1.sub(target2.point).length();
		target2.faceIndex = closestDistanceOtherTriIndex;
	}
	return target1;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/BufferUtils.js
function isSharedArrayBufferSupported() {
	return typeof SharedArrayBuffer !== "undefined";
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/cast/bvhcast.js
var _bufferStack1 = new BufferStack.constructor();
var _bufferStack2 = new BufferStack.constructor();
var _boxPool = new PrimitivePool(() => new Box3());
var _leftBox1 = new Box3();
var _rightBox1 = new Box3();
var _leftBox2 = new Box3();
var _rightBox2 = new Box3();
var _active = false;
function bvhcast(bvh, otherBvh, matrixToLocal, intersectsRanges) {
	if (_active) throw new Error("MeshBVH: Recursive calls to bvhcast not supported.");
	_active = true;
	const roots = bvh._roots;
	const otherRoots = otherBvh._roots;
	let result;
	let offset1 = 0;
	let offset2 = 0;
	const invMat = new Matrix4().copy(matrixToLocal).invert();
	for (let i = 0, il = roots.length; i < il; i++) {
		_bufferStack1.setBuffer(roots[i]);
		offset2 = 0;
		const localBox = _boxPool.getPrimitive();
		arrayToBox(BOUNDING_DATA_INDEX(0), _bufferStack1.float32Array, localBox);
		localBox.applyMatrix4(invMat);
		for (let j = 0, jl = otherRoots.length; j < jl; j++) {
			_bufferStack2.setBuffer(otherRoots[j]);
			result = _traverse(0, 0, matrixToLocal, invMat, intersectsRanges, offset1, offset2, 0, 0, localBox);
			_bufferStack2.clearBuffer();
			offset2 += otherRoots[j].length;
			if (result) break;
		}
		_boxPool.releasePrimitive(localBox);
		_bufferStack1.clearBuffer();
		offset1 += roots[i].length;
		if (result) break;
	}
	_active = false;
	return result;
}
function _traverse(node1Index32, node2Index32, matrix2to1, matrix1to2, intersectsRangesFunc, node1IndexByteOffset = 0, node2IndexByteOffset = 0, depth1 = 0, depth2 = 0, currBox = null, reversed = false) {
	let bufferStack1, bufferStack2;
	if (reversed) {
		bufferStack1 = _bufferStack2;
		bufferStack2 = _bufferStack1;
	} else {
		bufferStack1 = _bufferStack1;
		bufferStack2 = _bufferStack2;
	}
	const float32Array1 = bufferStack1.float32Array, uint32Array1 = bufferStack1.uint32Array, uint16Array1 = bufferStack1.uint16Array, float32Array2 = bufferStack2.float32Array, uint32Array2 = bufferStack2.uint32Array, uint16Array2 = bufferStack2.uint16Array;
	const node1Index16 = node1Index32 * 2;
	const node2Index16 = node2Index32 * 2;
	const isLeaf1 = IS_LEAF(node1Index16, uint16Array1);
	const isLeaf2 = IS_LEAF(node2Index16, uint16Array2);
	let result = false;
	if (isLeaf2 && isLeaf1) if (reversed) result = intersectsRangesFunc(OFFSET(node2Index32, uint32Array2), COUNT(node2Index32 * 2, uint16Array2), OFFSET(node1Index32, uint32Array1), COUNT(node1Index32 * 2, uint16Array1), depth2, node2IndexByteOffset + node2Index32, depth1, node1IndexByteOffset + node1Index32);
	else result = intersectsRangesFunc(OFFSET(node1Index32, uint32Array1), COUNT(node1Index32 * 2, uint16Array1), OFFSET(node2Index32, uint32Array2), COUNT(node2Index32 * 2, uint16Array2), depth1, node1IndexByteOffset + node1Index32, depth2, node2IndexByteOffset + node2Index32);
	else if (isLeaf2) {
		const newBox = _boxPool.getPrimitive();
		arrayToBox(BOUNDING_DATA_INDEX(node2Index32), float32Array2, newBox);
		newBox.applyMatrix4(matrix2to1);
		const cl1 = LEFT_NODE(node1Index32);
		const cr1 = RIGHT_NODE(node1Index32, uint32Array1);
		arrayToBox(BOUNDING_DATA_INDEX(cl1), float32Array1, _leftBox1);
		arrayToBox(BOUNDING_DATA_INDEX(cr1), float32Array1, _rightBox1);
		const intersectCl1 = newBox.intersectsBox(_leftBox1);
		const intersectCr1 = newBox.intersectsBox(_rightBox1);
		result = intersectCl1 && _traverse(node2Index32, cl1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed) || intersectCr1 && _traverse(node2Index32, cr1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed);
		_boxPool.releasePrimitive(newBox);
	} else {
		const cl2 = LEFT_NODE(node2Index32);
		const cr2 = RIGHT_NODE(node2Index32, uint32Array2);
		arrayToBox(BOUNDING_DATA_INDEX(cl2), float32Array2, _leftBox2);
		arrayToBox(BOUNDING_DATA_INDEX(cr2), float32Array2, _rightBox2);
		const leftIntersects = currBox.intersectsBox(_leftBox2);
		const rightIntersects = currBox.intersectsBox(_rightBox2);
		if (leftIntersects && rightIntersects) result = _traverse(node1Index32, cl2, matrix2to1, matrix1to2, intersectsRangesFunc, node1IndexByteOffset, node2IndexByteOffset, depth1, depth2 + 1, currBox, reversed) || _traverse(node1Index32, cr2, matrix2to1, matrix1to2, intersectsRangesFunc, node1IndexByteOffset, node2IndexByteOffset, depth1, depth2 + 1, currBox, reversed);
		else if (leftIntersects) if (isLeaf1) result = _traverse(node1Index32, cl2, matrix2to1, matrix1to2, intersectsRangesFunc, node1IndexByteOffset, node2IndexByteOffset, depth1, depth2 + 1, currBox, reversed);
		else {
			const newBox = _boxPool.getPrimitive();
			newBox.copy(_leftBox2).applyMatrix4(matrix2to1);
			const cl1 = LEFT_NODE(node1Index32);
			const cr1 = RIGHT_NODE(node1Index32, uint32Array1);
			arrayToBox(BOUNDING_DATA_INDEX(cl1), float32Array1, _leftBox1);
			arrayToBox(BOUNDING_DATA_INDEX(cr1), float32Array1, _rightBox1);
			const intersectCl1 = newBox.intersectsBox(_leftBox1);
			const intersectCr1 = newBox.intersectsBox(_rightBox1);
			result = intersectCl1 && _traverse(cl2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed) || intersectCr1 && _traverse(cl2, cr1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed);
			_boxPool.releasePrimitive(newBox);
		}
		else if (rightIntersects) if (isLeaf1) result = _traverse(node1Index32, cr2, matrix2to1, matrix1to2, intersectsRangesFunc, node1IndexByteOffset, node2IndexByteOffset, depth1, depth2 + 1, currBox, reversed);
		else {
			const newBox = _boxPool.getPrimitive();
			newBox.copy(_rightBox2).applyMatrix4(matrix2to1);
			const cl1 = LEFT_NODE(node1Index32);
			const cr1 = RIGHT_NODE(node1Index32, uint32Array1);
			arrayToBox(BOUNDING_DATA_INDEX(cl1), float32Array1, _leftBox1);
			arrayToBox(BOUNDING_DATA_INDEX(cr1), float32Array1, _rightBox1);
			const intersectCl1 = newBox.intersectsBox(_leftBox1);
			const intersectCr1 = newBox.intersectsBox(_rightBox1);
			result = intersectCl1 && _traverse(cr2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed) || intersectCr1 && _traverse(cr2, cr1, matrix1to2, matrix2to1, intersectsRangesFunc, node2IndexByteOffset, node1IndexByteOffset, depth2, depth1 + 1, newBox, !reversed);
			_boxPool.releasePrimitive(newBox);
		}
	}
	return result;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/core/MeshBVH.js
var obb = /* @__PURE__ */ new OrientedBox();
var tempBox = /* @__PURE__ */ new Box3();
var DEFAULT_OPTIONS = {
	strategy: 0,
	maxDepth: 40,
	maxLeafTris: 10,
	useSharedArrayBuffer: false,
	setBoundingBox: true,
	onProgress: null,
	indirect: false,
	verbose: true,
	range: null
};
var MeshBVH = class MeshBVH {
	static serialize(bvh, options = {}) {
		options = {
			cloneBuffers: true,
			...options
		};
		const geometry = bvh.geometry;
		const rootData = bvh._roots;
		const indirectBuffer = bvh._indirectBuffer;
		const indexAttribute = geometry.getIndex();
		let result;
		if (options.cloneBuffers) result = {
			roots: rootData.map((root) => root.slice()),
			index: indexAttribute ? indexAttribute.array.slice() : null,
			indirectBuffer: indirectBuffer ? indirectBuffer.slice() : null
		};
		else result = {
			roots: rootData,
			index: indexAttribute ? indexAttribute.array : null,
			indirectBuffer
		};
		return result;
	}
	static deserialize(data, geometry, options = {}) {
		options = {
			setIndex: true,
			indirect: Boolean(data.indirectBuffer),
			...options
		};
		const { index, roots, indirectBuffer } = data;
		const bvh = new MeshBVH(geometry, {
			...options,
			[SKIP_GENERATION]: true
		});
		bvh._roots = roots;
		bvh._indirectBuffer = indirectBuffer || null;
		if (options.setIndex) {
			const indexAttribute = geometry.getIndex();
			if (indexAttribute === null) {
				const newIndex = new BufferAttribute(data.index, 1, false);
				geometry.setIndex(newIndex);
			} else if (indexAttribute.array !== index) {
				indexAttribute.array.set(index);
				indexAttribute.needsUpdate = true;
			}
		}
		return bvh;
	}
	get indirect() {
		return !!this._indirectBuffer;
	}
	constructor(geometry, options = {}) {
		if (!geometry.isBufferGeometry) throw new Error("MeshBVH: Only BufferGeometries are supported.");
		else if (geometry.index && geometry.index.isInterleavedBufferAttribute) throw new Error("MeshBVH: InterleavedBufferAttribute is not supported for the index attribute.");
		options = Object.assign({
			...DEFAULT_OPTIONS,
			[SKIP_GENERATION]: false
		}, options);
		if (options.useSharedArrayBuffer && !isSharedArrayBufferSupported()) throw new Error("MeshBVH: SharedArrayBuffer is not available.");
		this.geometry = geometry;
		this._roots = null;
		this._indirectBuffer = null;
		if (!options[SKIP_GENERATION]) {
			buildPackedTree(this, options);
			if (!geometry.boundingBox && options.setBoundingBox) geometry.boundingBox = this.getBoundingBox(new Box3());
		}
		this.resolveTriangleIndex = options.indirect ? (i) => this._indirectBuffer[i] : (i) => i;
	}
	refit(nodeIndices = null) {
		return (this.indirect ? refit_indirect : refit)(this, nodeIndices);
	}
	traverse(callback, rootIndex = 0) {
		const buffer = this._roots[rootIndex];
		const uint32Array = new Uint32Array(buffer);
		const uint16Array = new Uint16Array(buffer);
		_traverse(0);
		function _traverse(node32Index, depth = 0) {
			const node16Index = node32Index * 2;
			const isLeaf = uint16Array[node16Index + 15] === IS_LEAFNODE_FLAG;
			if (isLeaf) {
				const offset = uint32Array[node32Index + 6];
				const count = uint16Array[node16Index + 14];
				callback(depth, isLeaf, new Float32Array(buffer, node32Index * 4, 6), offset, count);
			} else {
				const left = node32Index + 32 / 4;
				const right = uint32Array[node32Index + 6];
				const splitAxis = uint32Array[node32Index + 7];
				if (!callback(depth, isLeaf, new Float32Array(buffer, node32Index * 4, 6), splitAxis)) {
					_traverse(left, depth + 1);
					_traverse(right, depth + 1);
				}
			}
		}
	}
	raycast(ray, materialOrSide = 0, near = 0, far = Infinity) {
		const roots = this._roots;
		const geometry = this.geometry;
		const intersects = [];
		const isMaterial = materialOrSide.isMaterial;
		const isArrayMaterial = Array.isArray(materialOrSide);
		const groups = geometry.groups;
		const side = isMaterial ? materialOrSide.side : materialOrSide;
		const raycastFunc = this.indirect ? raycast_indirect : raycast;
		for (let i = 0, l = roots.length; i < l; i++) {
			const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side;
			const startCount = intersects.length;
			raycastFunc(this, i, materialSide, ray, intersects, near, far);
			if (isArrayMaterial) {
				const materialIndex = groups[i].materialIndex;
				for (let j = startCount, jl = intersects.length; j < jl; j++) intersects[j].face.materialIndex = materialIndex;
			}
		}
		return intersects;
	}
	raycastFirst(ray, materialOrSide = 0, near = 0, far = Infinity) {
		const roots = this._roots;
		const geometry = this.geometry;
		const isMaterial = materialOrSide.isMaterial;
		const isArrayMaterial = Array.isArray(materialOrSide);
		let closestResult = null;
		const groups = geometry.groups;
		const side = isMaterial ? materialOrSide.side : materialOrSide;
		const raycastFirstFunc = this.indirect ? raycastFirst_indirect : raycastFirst;
		for (let i = 0, l = roots.length; i < l; i++) {
			const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side;
			const result = raycastFirstFunc(this, i, materialSide, ray, near, far);
			if (result != null && (closestResult == null || result.distance < closestResult.distance)) {
				closestResult = result;
				if (isArrayMaterial) result.face.materialIndex = groups[i].materialIndex;
			}
		}
		return closestResult;
	}
	intersectsGeometry(otherGeometry, geomToMesh) {
		let result = false;
		const roots = this._roots;
		const intersectsGeometryFunc = this.indirect ? intersectsGeometry_indirect : intersectsGeometry;
		for (let i = 0, l = roots.length; i < l; i++) {
			result = intersectsGeometryFunc(this, i, otherGeometry, geomToMesh);
			if (result) break;
		}
		return result;
	}
	shapecast(callbacks) {
		const triangle = ExtendedTrianglePool.getPrimitive();
		const iterateFunc = this.indirect ? iterateOverTriangles_indirect : iterateOverTriangles;
		let { boundsTraverseOrder, intersectsBounds, intersectsRange, intersectsTriangle } = callbacks;
		if (intersectsRange && intersectsTriangle) {
			const originalIntersectsRange = intersectsRange;
			intersectsRange = (offset, count, contained, depth, nodeIndex) => {
				if (!originalIntersectsRange(offset, count, contained, depth, nodeIndex)) return iterateFunc(offset, count, this, intersectsTriangle, contained, depth, triangle);
				return true;
			};
		} else if (!intersectsRange) if (intersectsTriangle) intersectsRange = (offset, count, contained, depth) => {
			return iterateFunc(offset, count, this, intersectsTriangle, contained, depth, triangle);
		};
		else intersectsRange = (offset, count, contained) => {
			return contained;
		};
		let result = false;
		let byteOffset = 0;
		const roots = this._roots;
		for (let i = 0, l = roots.length; i < l; i++) {
			const root = roots[i];
			result = shapecast(this, i, intersectsBounds, intersectsRange, boundsTraverseOrder, byteOffset);
			if (result) break;
			byteOffset += root.byteLength;
		}
		ExtendedTrianglePool.releasePrimitive(triangle);
		return result;
	}
	bvhcast(otherBvh, matrixToLocal, callbacks) {
		let { intersectsRanges, intersectsTriangles } = callbacks;
		const triangle1 = ExtendedTrianglePool.getPrimitive();
		const indexAttr1 = this.geometry.index;
		const positionAttr1 = this.geometry.attributes.position;
		const assignTriangle1 = this.indirect ? (i1) => {
			setTriangle(triangle1, this.resolveTriangleIndex(i1) * 3, indexAttr1, positionAttr1);
		} : (i1) => {
			setTriangle(triangle1, i1 * 3, indexAttr1, positionAttr1);
		};
		const triangle2 = ExtendedTrianglePool.getPrimitive();
		const indexAttr2 = otherBvh.geometry.index;
		const positionAttr2 = otherBvh.geometry.attributes.position;
		const assignTriangle2 = otherBvh.indirect ? (i2) => {
			setTriangle(triangle2, otherBvh.resolveTriangleIndex(i2) * 3, indexAttr2, positionAttr2);
		} : (i2) => {
			setTriangle(triangle2, i2 * 3, indexAttr2, positionAttr2);
		};
		if (intersectsTriangles) {
			const iterateOverDoubleTriangles = (offset1, count1, offset2, count2, depth1, index1, depth2, index2) => {
				for (let i2 = offset2, l2 = offset2 + count2; i2 < l2; i2++) {
					assignTriangle2(i2);
					triangle2.a.applyMatrix4(matrixToLocal);
					triangle2.b.applyMatrix4(matrixToLocal);
					triangle2.c.applyMatrix4(matrixToLocal);
					triangle2.needsUpdate = true;
					for (let i1 = offset1, l1 = offset1 + count1; i1 < l1; i1++) {
						assignTriangle1(i1);
						triangle1.needsUpdate = true;
						if (intersectsTriangles(triangle1, triangle2, i1, i2, depth1, index1, depth2, index2)) return true;
					}
				}
				return false;
			};
			if (intersectsRanges) {
				const originalIntersectsRanges = intersectsRanges;
				intersectsRanges = function(offset1, count1, offset2, count2, depth1, index1, depth2, index2) {
					if (!originalIntersectsRanges(offset1, count1, offset2, count2, depth1, index1, depth2, index2)) return iterateOverDoubleTriangles(offset1, count1, offset2, count2, depth1, index1, depth2, index2);
					return true;
				};
			} else intersectsRanges = iterateOverDoubleTriangles;
		}
		return bvhcast(this, otherBvh, matrixToLocal, intersectsRanges);
	}
	intersectsBox(box, boxToMesh) {
		obb.set(box.min, box.max, boxToMesh);
		obb.needsUpdate = true;
		return this.shapecast({
			intersectsBounds: (box) => obb.intersectsBox(box),
			intersectsTriangle: (tri) => obb.intersectsTriangle(tri)
		});
	}
	intersectsSphere(sphere) {
		return this.shapecast({
			intersectsBounds: (box) => sphere.intersectsBox(box),
			intersectsTriangle: (tri) => tri.intersectsSphere(sphere)
		});
	}
	closestPointToGeometry(otherGeometry, geometryToBvh, target1 = {}, target2 = {}, minThreshold = 0, maxThreshold = Infinity) {
		return (this.indirect ? closestPointToGeometry_indirect : closestPointToGeometry)(this, otherGeometry, geometryToBvh, target1, target2, minThreshold, maxThreshold);
	}
	closestPointToPoint(point, target = {}, minThreshold = 0, maxThreshold = Infinity) {
		return closestPointToPoint(this, point, target, minThreshold, maxThreshold);
	}
	getBoundingBox(target) {
		target.makeEmpty();
		this._roots.forEach((buffer) => {
			arrayToBox(0, new Float32Array(buffer), tempBox);
			target.union(tempBox);
		});
		return target;
	}
};
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/GeometryRayIntersectUtilities.js
function convertRaycastIntersect(hit, object, raycaster) {
	if (hit === null) return null;
	hit.point.applyMatrix4(object.matrixWorld);
	hit.distance = hit.point.distanceTo(raycaster.ray.origin);
	hit.object = object;
	return hit;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/utils/ExtensionUtilities.js
var ray$2 = /* @__PURE__ */ new Ray();
var direction = /* @__PURE__ */ new Vector3();
var tmpInverseMatrix = /* @__PURE__ */ new Matrix4();
var origMeshRaycastFunc = Mesh.prototype.raycast;
var origBatchedRaycastFunc = BatchedMesh.prototype.raycast;
var _worldScale = /* @__PURE__ */ new Vector3();
var _mesh$1 = /* @__PURE__ */ new Mesh();
var _batchIntersects = [];
function acceleratedRaycast(raycaster, intersects) {
	if (this.isBatchedMesh) acceleratedBatchedMeshRaycast.call(this, raycaster, intersects);
	else acceleratedMeshRaycast.call(this, raycaster, intersects);
}
function acceleratedBatchedMeshRaycast(raycaster, intersects) {
	if (this.boundsTrees) {
		const boundsTrees = this.boundsTrees;
		const drawInfo = this._drawInfo || this._instanceInfo;
		const drawRanges = this._drawRanges || this._geometryInfo;
		const matrixWorld = this.matrixWorld;
		_mesh$1.material = this.material;
		_mesh$1.geometry = this.geometry;
		const oldBoundsTree = _mesh$1.geometry.boundsTree;
		const oldDrawRange = _mesh$1.geometry.drawRange;
		if (_mesh$1.geometry.boundingSphere === null) _mesh$1.geometry.boundingSphere = new Sphere$1();
		for (let i = 0, l = drawInfo.length; i < l; i++) {
			if (!this.getVisibleAt(i)) continue;
			const geometryId = drawInfo[i].geometryIndex;
			_mesh$1.geometry.boundsTree = boundsTrees[geometryId];
			this.getMatrixAt(i, _mesh$1.matrixWorld).premultiply(matrixWorld);
			if (!_mesh$1.geometry.boundsTree) {
				this.getBoundingBoxAt(geometryId, _mesh$1.geometry.boundingBox);
				this.getBoundingSphereAt(geometryId, _mesh$1.geometry.boundingSphere);
				const drawRange = drawRanges[geometryId];
				_mesh$1.geometry.setDrawRange(drawRange.start, drawRange.count);
			}
			_mesh$1.raycast(raycaster, _batchIntersects);
			for (let j = 0, l = _batchIntersects.length; j < l; j++) {
				const intersect = _batchIntersects[j];
				intersect.object = this;
				intersect.batchId = i;
				intersects.push(intersect);
			}
			_batchIntersects.length = 0;
		}
		_mesh$1.geometry.boundsTree = oldBoundsTree;
		_mesh$1.geometry.drawRange = oldDrawRange;
		_mesh$1.material = null;
		_mesh$1.geometry = null;
	} else origBatchedRaycastFunc.call(this, raycaster, intersects);
}
function acceleratedMeshRaycast(raycaster, intersects) {
	if (this.geometry.boundsTree) {
		if (this.material === void 0) return;
		tmpInverseMatrix.copy(this.matrixWorld).invert();
		ray$2.copy(raycaster.ray).applyMatrix4(tmpInverseMatrix);
		_worldScale.setFromMatrixScale(this.matrixWorld);
		direction.copy(ray$2.direction).multiply(_worldScale);
		const scaleFactor = direction.length();
		const near = raycaster.near / scaleFactor;
		const far = raycaster.far / scaleFactor;
		const bvh = this.geometry.boundsTree;
		if (raycaster.firstHitOnly === true) {
			const hit = convertRaycastIntersect(bvh.raycastFirst(ray$2, this.material, near, far), this, raycaster);
			if (hit) intersects.push(hit);
		} else {
			const hits = bvh.raycast(ray$2, this.material, near, far);
			for (let i = 0, l = hits.length; i < l; i++) {
				const hit = convertRaycastIntersect(hits[i], this, raycaster);
				if (hit) intersects.push(hit);
			}
		}
	} else origMeshRaycastFunc.call(this, raycaster, intersects);
}
function computeBoundsTree(options = {}) {
	this.boundsTree = new MeshBVH(this, options);
	return this.boundsTree;
}
function disposeBoundsTree() {
	this.boundsTree = null;
}
//#endregion
//#region node_modules/three-mesh-bvh/src/gpu/VertexAttributeTexture.js
function countToStringFormat(count) {
	switch (count) {
		case 1: return "R";
		case 2: return "RG";
		case 3: return "RGBA";
		case 4: return "RGBA";
	}
	throw new Error();
}
function countToFormat(count) {
	switch (count) {
		case 1: return RedFormat;
		case 2: return RGFormat;
		case 3: return RGBAFormat;
		case 4: return RGBAFormat;
	}
}
function countToIntFormat(count) {
	switch (count) {
		case 1: return RedIntegerFormat;
		case 2: return RGIntegerFormat;
		case 3: return RGBAIntegerFormat;
		case 4: return RGBAIntegerFormat;
	}
}
var VertexAttributeTexture = class extends DataTexture {
	constructor() {
		super();
		this.minFilter = NearestFilter;
		this.magFilter = NearestFilter;
		this.generateMipmaps = false;
		this.overrideItemSize = null;
		this._forcedType = null;
	}
	updateFrom(attr) {
		const overrideItemSize = this.overrideItemSize;
		const originalItemSize = attr.itemSize;
		const originalCount = attr.count;
		if (overrideItemSize !== null) {
			if (originalItemSize * originalCount % overrideItemSize !== 0) throw new Error("VertexAttributeTexture: overrideItemSize must divide evenly into buffer length.");
			attr.itemSize = overrideItemSize;
			attr.count = originalCount * originalItemSize / overrideItemSize;
		}
		const itemSize = attr.itemSize;
		const count = attr.count;
		const normalized = attr.normalized;
		const originalBufferCons = attr.array.constructor;
		const byteCount = originalBufferCons.BYTES_PER_ELEMENT;
		let targetType = this._forcedType;
		let finalStride = itemSize;
		if (targetType === null) switch (originalBufferCons) {
			case Float32Array:
				targetType = FloatType;
				break;
			case Uint8Array:
			case Uint16Array:
			case Uint32Array:
				targetType = UnsignedIntType;
				break;
			case Int8Array:
			case Int16Array:
			case Int32Array:
				targetType = IntType;
				break;
		}
		let type, format, normalizeValue, targetBufferCons;
		let internalFormat = countToStringFormat(itemSize);
		switch (targetType) {
			case FloatType:
				normalizeValue = 1;
				format = countToFormat(itemSize);
				if (normalized && byteCount === 1) {
					targetBufferCons = originalBufferCons;
					internalFormat += "8";
					if (originalBufferCons === Uint8Array) type = UnsignedByteType;
					else {
						type = ByteType;
						internalFormat += "_SNORM";
					}
				} else {
					targetBufferCons = Float32Array;
					internalFormat += "32F";
					type = FloatType;
				}
				break;
			case IntType:
				internalFormat += byteCount * 8 + "I";
				normalizeValue = normalized ? Math.pow(2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1) : 1;
				format = countToIntFormat(itemSize);
				if (byteCount === 1) {
					targetBufferCons = Int8Array;
					type = ByteType;
				} else if (byteCount === 2) {
					targetBufferCons = Int16Array;
					type = ShortType;
				} else {
					targetBufferCons = Int32Array;
					type = IntType;
				}
				break;
			case UnsignedIntType:
				internalFormat += byteCount * 8 + "UI";
				normalizeValue = normalized ? Math.pow(2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1) : 1;
				format = countToIntFormat(itemSize);
				if (byteCount === 1) {
					targetBufferCons = Uint8Array;
					type = UnsignedByteType;
				} else if (byteCount === 2) {
					targetBufferCons = Uint16Array;
					type = UnsignedShortType;
				} else {
					targetBufferCons = Uint32Array;
					type = UnsignedIntType;
				}
				break;
		}
		if (finalStride === 3 && (format === 1023 || format === 1033)) finalStride = 4;
		const dimension = Math.ceil(Math.sqrt(count)) || 1;
		const length = finalStride * dimension * dimension;
		const dataArray = new targetBufferCons(length);
		const originalNormalized = attr.normalized;
		attr.normalized = false;
		for (let i = 0; i < count; i++) {
			const ii = finalStride * i;
			dataArray[ii] = attr.getX(i) / normalizeValue;
			if (itemSize >= 2) dataArray[ii + 1] = attr.getY(i) / normalizeValue;
			if (itemSize >= 3) {
				dataArray[ii + 2] = attr.getZ(i) / normalizeValue;
				if (finalStride === 4) dataArray[ii + 3] = 1;
			}
			if (itemSize >= 4) dataArray[ii + 3] = attr.getW(i) / normalizeValue;
		}
		attr.normalized = originalNormalized;
		this.internalFormat = internalFormat;
		this.format = format;
		this.type = type;
		this.image.width = dimension;
		this.image.height = dimension;
		this.image.data = dataArray;
		this.needsUpdate = true;
		this.dispose();
		attr.itemSize = originalItemSize;
		attr.count = originalCount;
	}
};
var UIntVertexAttributeTexture = class extends VertexAttributeTexture {
	constructor() {
		super();
		this._forcedType = UnsignedIntType;
	}
};
var FloatVertexAttributeTexture = class extends VertexAttributeTexture {
	constructor() {
		super();
		this._forcedType = FloatType;
	}
};
//#endregion
//#region node_modules/three-mesh-bvh/src/gpu/MeshBVHUniformStruct.js
var MeshBVHUniformStruct = class {
	constructor() {
		this.index = new UIntVertexAttributeTexture();
		this.position = new FloatVertexAttributeTexture();
		this.bvhBounds = new DataTexture();
		this.bvhContents = new DataTexture();
		this._cachedIndexAttr = null;
		this.index.overrideItemSize = 3;
	}
	updateFrom(bvh) {
		const { geometry } = bvh;
		bvhToTextures(bvh, this.bvhBounds, this.bvhContents);
		this.position.updateFrom(geometry.attributes.position);
		if (bvh.indirect) {
			const indirectBuffer = bvh._indirectBuffer;
			if (this._cachedIndexAttr === null || this._cachedIndexAttr.count !== indirectBuffer.length) if (geometry.index) this._cachedIndexAttr = geometry.index.clone();
			else {
				const array = getIndexArray(getVertexCount(geometry));
				this._cachedIndexAttr = new BufferAttribute(array, 1, false);
			}
			dereferenceIndex(geometry, indirectBuffer, this._cachedIndexAttr);
			this.index.updateFrom(this._cachedIndexAttr);
		} else this.index.updateFrom(geometry.index);
	}
	dispose() {
		const { index, position, bvhBounds, bvhContents } = this;
		if (index) index.dispose();
		if (position) position.dispose();
		if (bvhBounds) bvhBounds.dispose();
		if (bvhContents) bvhContents.dispose();
	}
};
function dereferenceIndex(geometry, indirectBuffer, target) {
	const unpacked = target.array;
	const indexArray = geometry.index ? geometry.index.array : null;
	for (let i = 0, l = indirectBuffer.length; i < l; i++) {
		const i3 = 3 * i;
		const v3 = 3 * indirectBuffer[i];
		for (let c = 0; c < 3; c++) unpacked[i3 + c] = indexArray ? indexArray[v3 + c] : v3 + c;
	}
}
function bvhToTextures(bvh, boundsTexture, contentsTexture) {
	const roots = bvh._roots;
	if (roots.length !== 1) throw new Error("MeshBVHUniformStruct: Multi-root BVHs not supported.");
	const root = roots[0];
	const uint16Array = new Uint16Array(root);
	const uint32Array = new Uint32Array(root);
	const float32Array = new Float32Array(root);
	const nodeCount = root.byteLength / 32;
	const boundsDimension = 2 * Math.ceil(Math.sqrt(nodeCount / 2));
	const boundsArray = new Float32Array(4 * boundsDimension * boundsDimension);
	const contentsDimension = Math.ceil(Math.sqrt(nodeCount));
	const contentsArray = new Uint32Array(2 * contentsDimension * contentsDimension);
	for (let i = 0; i < nodeCount; i++) {
		const nodeIndex32 = i * 32 / 4;
		const nodeIndex16 = nodeIndex32 * 2;
		const boundsIndex = BOUNDING_DATA_INDEX(nodeIndex32);
		for (let b = 0; b < 3; b++) {
			boundsArray[8 * i + 0 + b] = float32Array[boundsIndex + 0 + b];
			boundsArray[8 * i + 4 + b] = float32Array[boundsIndex + 3 + b];
		}
		if (IS_LEAF(nodeIndex16, uint16Array)) {
			const count = COUNT(nodeIndex16, uint16Array);
			const offset = OFFSET(nodeIndex32, uint32Array);
			const mergedLeafCount = 4294901760 | count;
			contentsArray[i * 2 + 0] = mergedLeafCount;
			contentsArray[i * 2 + 1] = offset;
		} else {
			const rightIndex = 4 * RIGHT_NODE(nodeIndex32, uint32Array) / 32;
			const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array);
			contentsArray[i * 2 + 0] = splitAxis;
			contentsArray[i * 2 + 1] = rightIndex;
		}
	}
	boundsTexture.image.data = boundsArray;
	boundsTexture.image.width = boundsDimension;
	boundsTexture.image.height = boundsDimension;
	boundsTexture.format = RGBAFormat;
	boundsTexture.type = FloatType;
	boundsTexture.internalFormat = "RGBA32F";
	boundsTexture.minFilter = NearestFilter;
	boundsTexture.magFilter = NearestFilter;
	boundsTexture.generateMipmaps = false;
	boundsTexture.needsUpdate = true;
	boundsTexture.dispose();
	contentsTexture.image.data = contentsArray;
	contentsTexture.image.width = contentsDimension;
	contentsTexture.image.height = contentsDimension;
	contentsTexture.format = RGIntegerFormat;
	contentsTexture.type = UnsignedIntType;
	contentsTexture.internalFormat = "RG32UI";
	contentsTexture.minFilter = NearestFilter;
	contentsTexture.magFilter = NearestFilter;
	contentsTexture.generateMipmaps = false;
	contentsTexture.needsUpdate = true;
	contentsTexture.dispose();
}
//#endregion
//#region node_modules/three-mesh-bvh/src/gpu/glsl/common_functions.glsl.js
var common_functions = `

// A stack of uint32 indices can can store the indices for
// a perfectly balanced tree with a depth up to 31. Lower stack
// depth gets higher performance.
//
// However not all trees are balanced. Best value to set this to
// is the trees max depth.
#ifndef BVH_STACK_DEPTH
#define BVH_STACK_DEPTH 60
#endif

#ifndef INFINITY
#define INFINITY 1e20
#endif

// Utilities
uvec4 uTexelFetch1D( usampler2D tex, uint index ) {

	uint width = uint( textureSize( tex, 0 ).x );
	uvec2 uv;
	uv.x = index % width;
	uv.y = index / width;

	return texelFetch( tex, ivec2( uv ), 0 );

}

ivec4 iTexelFetch1D( isampler2D tex, uint index ) {

	uint width = uint( textureSize( tex, 0 ).x );
	uvec2 uv;
	uv.x = index % width;
	uv.y = index / width;

	return texelFetch( tex, ivec2( uv ), 0 );

}

vec4 texelFetch1D( sampler2D tex, uint index ) {

	uint width = uint( textureSize( tex, 0 ).x );
	uvec2 uv;
	uv.x = index % width;
	uv.y = index / width;

	return texelFetch( tex, ivec2( uv ), 0 );

}

vec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {

	return
		barycoord.x * texelFetch1D( tex, faceIndices.x ) +
		barycoord.y * texelFetch1D( tex, faceIndices.y ) +
		barycoord.z * texelFetch1D( tex, faceIndices.z );

}

void ndcToCameraRay(
	vec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,
	out vec3 rayOrigin, out vec3 rayDirection
) {

	// get camera look direction and near plane for camera clipping
	vec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );
	vec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );
	float near = abs( nearVector.z / nearVector.w );

	// get the camera direction and position from camera matrices
	vec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );
	vec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );
	direction /= direction.w;
	direction = cameraWorld * direction - origin;

	// slide the origin along the ray until it sits at the near clip plane position
	origin.xyz += direction.xyz * near / dot( direction, lookDirection );

	rayOrigin = origin.xyz;
	rayDirection = direction.xyz;

}
`;
//#endregion
//#region node_modules/three-mesh-bvh/src/gpu/glsl/bvh_ray_functions.glsl.js
var bvh_ray_functions = `

#ifndef TRI_INTERSECT_EPSILON
#define TRI_INTERSECT_EPSILON 1e-5
#endif

// Raycasting
bool intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax, out float dist ) {

	// https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/
	// https://tavianator.com/2011/ray_box.html
	vec3 invDir = 1.0 / rayDirection;

	// find intersection distances for each plane
	vec3 tMinPlane = invDir * ( boundsMin - rayOrigin );
	vec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );

	// get the min and max distances from each intersection
	vec3 tMinHit = min( tMaxPlane, tMinPlane );
	vec3 tMaxHit = max( tMaxPlane, tMinPlane );

	// get the furthest hit distance
	vec2 t = max( tMinHit.xx, tMinHit.yz );
	float t0 = max( t.x, t.y );

	// get the minimum hit distance
	t = min( tMaxHit.xx, tMaxHit.yz );
	float t1 = min( t.x, t.y );

	// set distance to 0.0 if the ray starts inside the box
	dist = max( t0, 0.0 );

	return t1 >= dist;

}

bool intersectsTriangle(
	vec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,
	out vec3 barycoord, out vec3 norm, out float dist, out float side
) {

	// https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d
	vec3 edge1 = b - a;
	vec3 edge2 = c - a;
	norm = cross( edge1, edge2 );

	float det = - dot( rayDirection, norm );
	float invdet = 1.0 / det;

	vec3 AO = rayOrigin - a;
	vec3 DAO = cross( AO, rayDirection );

	vec4 uvt;
	uvt.x = dot( edge2, DAO ) * invdet;
	uvt.y = - dot( edge1, DAO ) * invdet;
	uvt.z = dot( AO, norm ) * invdet;
	uvt.w = 1.0 - uvt.x - uvt.y;

	// set the hit information
	barycoord = uvt.wxy; // arranged in A, B, C order
	dist = uvt.z;
	side = sign( det );
	norm = side * normalize( norm );

	// add an epsilon to avoid misses between triangles
	uvt += vec4( TRI_INTERSECT_EPSILON );

	return all( greaterThanEqual( uvt, vec4( 0.0 ) ) );

}

bool intersectTriangles(
	// geometry info and triangle range
	sampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,

	// ray
	vec3 rayOrigin, vec3 rayDirection,

	// outputs
	inout float minDistance, inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,
	inout float side, inout float dist
) {

	bool found = false;
	vec3 localBarycoord, localNormal;
	float localDist, localSide;
	for ( uint i = offset, l = offset + count; i < l; i ++ ) {

		uvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;
		vec3 a = texelFetch1D( positionAttr, indices.x ).rgb;
		vec3 b = texelFetch1D( positionAttr, indices.y ).rgb;
		vec3 c = texelFetch1D( positionAttr, indices.z ).rgb;

		if (
			intersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )
			&& localDist < minDistance
		) {

			found = true;
			minDistance = localDist;

			faceIndices = uvec4( indices.xyz, i );
			faceNormal = localNormal;

			side = localSide;
			barycoord = localBarycoord;
			dist = localDist;

		}

	}

	return found;

}

bool intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, sampler2D bvhBounds, uint currNodeIndex, out float dist ) {

	uint cni2 = currNodeIndex * 2u;
	vec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;
	vec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;
	return intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax, dist );

}

// use a macro to hide the fact that we need to expand the struct into separate fields
#define\
	bvhIntersectFirstHit(\
		bvh,\
		rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist\
	)\
	_bvhIntersectFirstHit(\
		bvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents,\
		rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist\
	)

bool _bvhIntersectFirstHit(
	// bvh info
	sampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,

	// ray
	vec3 rayOrigin, vec3 rayDirection,

	// output variables split into separate variables due to output precision
	inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,
	inout float side, inout float dist
) {

	// stack needs to be twice as long as the deepest tree we expect because
	// we push both the left and right child onto the stack every traversal
	int ptr = 0;
	uint stack[ BVH_STACK_DEPTH ];
	stack[ 0 ] = 0u;

	float triangleDistance = INFINITY;
	bool found = false;
	while ( ptr > - 1 && ptr < BVH_STACK_DEPTH ) {

		uint currNodeIndex = stack[ ptr ];
		ptr --;

		// check if we intersect the current bounds
		float boundsHitDistance;
		if (
			! intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh_bvhBounds, currNodeIndex, boundsHitDistance )
			|| boundsHitDistance > triangleDistance
		) {

			continue;

		}

		uvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;
		bool isLeaf = bool( boundsInfo.x & 0xffff0000u );

		if ( isLeaf ) {

			uint count = boundsInfo.x & 0x0000ffffu;
			uint offset = boundsInfo.y;

			found = intersectTriangles(
				bvh_position, bvh_index, offset, count,
				rayOrigin, rayDirection, triangleDistance,
				faceIndices, faceNormal, barycoord, side, dist
			) || found;

		} else {

			uint leftIndex = currNodeIndex + 1u;
			uint splitAxis = boundsInfo.x & 0x0000ffffu;
			uint rightIndex = boundsInfo.y;

			bool leftToRight = rayDirection[ splitAxis ] >= 0.0;
			uint c1 = leftToRight ? leftIndex : rightIndex;
			uint c2 = leftToRight ? rightIndex : leftIndex;

			// set c2 in the stack so we traverse it later. We need to keep track of a pointer in
			// the stack while we traverse. The second pointer added is the one that will be
			// traversed first
			ptr ++;
			stack[ ptr ] = c2;

			ptr ++;
			stack[ ptr ] = c1;

		}

	}

	return found;

}
`;
//#endregion
//#region node_modules/three-mesh-bvh/src/index.js
var shaderStructs = `
struct BVH {

	usampler2D index;
	sampler2D position;

	sampler2D bvhBounds;
	usampler2D bvhContents;

};
`;
var shaderIntersectFunction = `
	${common_functions}
	${bvh_ray_functions}
`;
//#endregion
//#region node_modules/@react-three/drei/core/Bvh.js
var isMesh = (child) => child.isMesh;
/**
* @deprecated Use the Bvh component instead
*/
function useBVH(mesh, options) {
	options = {
		strategy: 2,
		verbose: false,
		setBoundingBox: true,
		maxDepth: 40,
		maxLeafTris: 10,
		indirect: false,
		...options
	};
	import_react.useEffect(() => {
		if (mesh.current) {
			mesh.current.raycast = acceleratedRaycast;
			const geometry = mesh.current.geometry;
			geometry.computeBoundsTree = computeBoundsTree;
			geometry.disposeBoundsTree = disposeBoundsTree;
			geometry.computeBoundsTree(options);
			return () => {
				if (geometry.boundsTree) geometry.disposeBoundsTree();
			};
		}
	}, [mesh, JSON.stringify(options)]);
}
var Bvh = /* @__PURE__ */ import_react.forwardRef(({ enabled = true, firstHitOnly = false, children, strategy = 2, verbose = false, setBoundingBox = true, maxDepth = 40, maxLeafTris = 10, indirect = false, ...props }, fref) => {
	const ref = import_react.useRef(null);
	const raycaster = useThree((state) => state.raycaster);
	import_react.useImperativeHandle(fref, () => ref.current, []);
	import_react.useEffect(() => {
		if (enabled) {
			const options = {
				strategy,
				verbose,
				setBoundingBox,
				maxDepth,
				maxLeafTris,
				indirect
			};
			const group = ref.current;
			raycaster.firstHitOnly = firstHitOnly;
			group.traverse((child) => {
				if (isMesh(child) && !child.geometry.boundsTree && child.raycast === Mesh.prototype.raycast) {
					child.raycast = acceleratedRaycast;
					child.geometry.computeBoundsTree = computeBoundsTree;
					child.geometry.disposeBoundsTree = disposeBoundsTree;
					child.geometry.computeBoundsTree(options);
				}
			});
			return () => {
				delete raycaster.firstHitOnly;
				group.traverse((child) => {
					if (isMesh(child) && child.geometry.boundsTree) {
						child.geometry.disposeBoundsTree();
						child.raycast = Mesh.prototype.raycast;
					}
				});
			};
		}
	}, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props), children);
});
//#endregion
//#region node_modules/@react-three/drei/core/useContextBridge.js
function useContextBridge(...contexts) {
	const cRef = import_react.useRef([]);
	cRef.current = contexts.map((context) => import_react.useContext(context));
	return import_react.useMemo(() => ({ children }) => contexts.reduceRight((acc, Context, i) => /*#__PURE__*/ import_react.createElement(Context.Provider, {
		value: cRef.current[i],
		children: acc
	}), children), []);
}
//#endregion
//#region node_modules/@react-three/drei/core/useAnimations.js
function useAnimations(clips, root) {
	const ref = import_react.useRef(null);
	const [actualRef] = import_react.useState(() => root ? root instanceof Object3D ? { current: root } : root : ref);
	const [mixer] = import_react.useState(() => new AnimationMixer(void 0));
	import_react.useLayoutEffect(() => {
		if (root) actualRef.current = root instanceof Object3D ? root : root.current;
		mixer._root = actualRef.current;
	});
	const lazyActions = import_react.useRef({});
	const api = import_react.useMemo(() => {
		const actions = {};
		clips.forEach((clip) => Object.defineProperty(actions, clip.name, {
			enumerable: true,
			get() {
				if (actualRef.current) return lazyActions.current[clip.name] || (lazyActions.current[clip.name] = mixer.clipAction(clip, actualRef.current));
			},
			configurable: true
		}));
		return {
			ref: actualRef,
			clips,
			actions,
			names: clips.map((c) => c.name),
			mixer
		};
	}, [clips]);
	useFrame((state, delta) => mixer.update(delta));
	import_react.useEffect(() => {
		const currentRoot = actualRef.current;
		return () => {
			lazyActions.current = {};
			mixer.stopAllAction();
			Object.values(api.actions).forEach((action) => {
				if (currentRoot) mixer.uncacheAction(action, currentRoot);
			});
		};
	}, [clips]);
	return api;
}
//#endregion
//#region node_modules/@react-three/drei/core/useIntersect.js
function useIntersect(onChange) {
	const ref = import_react.useRef(null);
	const check = import_react.useRef(false);
	const temp = import_react.useRef(false);
	const callback = import_react.useRef(onChange);
	import_react.useLayoutEffect(() => void (callback.current = onChange), [onChange]);
	import_react.useEffect(() => {
		const obj = ref.current;
		if (obj) {
			const unsub1 = addEffect(() => {
				check.current = false;
				return true;
			});
			const oldOnRender = obj.onBeforeRender;
			obj.onBeforeRender = () => check.current = true;
			const unsub2 = addAfterEffect(() => {
				if (check.current !== temp.current) callback.current == null || callback.current(temp.current = check.current);
				return true;
			});
			return () => {
				obj.onBeforeRender = oldOnRender;
				unsub1();
				unsub2();
			};
		}
	}, []);
	return ref;
}
//#endregion
//#region node_modules/@react-three/drei/core/useBoxProjectedEnv.js
var worldposReplace = `
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )
  vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );
  #ifdef BOX_PROJECTED_ENV_MAP
    vWorldPosition = worldPosition.xyz;
  #endif
#endif
`;
var boxProjectDefinitions = `
#ifdef BOX_PROJECTED_ENV_MAP
  uniform vec3 envMapSize;
  uniform vec3 envMapPosition;
  varying vec3 vWorldPosition;
    
  vec3 parallaxCorrectNormal( vec3 v, vec3 cubeSize, vec3 cubePos ) {
    vec3 nDir = normalize( v );
    vec3 rbmax = ( .5 * cubeSize + cubePos - vWorldPosition ) / nDir;
    vec3 rbmin = ( -.5 * cubeSize + cubePos - vWorldPosition ) / nDir;
    vec3 rbminmax;
    rbminmax.x = ( nDir.x > 0. ) ? rbmax.x : rbmin.x;
    rbminmax.y = ( nDir.y > 0. ) ? rbmax.y : rbmin.y;
    rbminmax.z = ( nDir.z > 0. ) ? rbmax.z : rbmin.z;
    float correction = min( min( rbminmax.x, rbminmax.y ), rbminmax.z );
    vec3 boxIntersection = vWorldPosition + nDir * correction;    
    return boxIntersection - cubePos;
  }
#endif
`;
var getIBLIrradiance_patch = `
#ifdef BOX_PROJECTED_ENV_MAP
  worldNormal = parallaxCorrectNormal( worldNormal, envMapSize, envMapPosition );
#endif
`;
var getIBLRadiance_patch = `
#ifdef BOX_PROJECTED_ENV_MAP
  reflectVec = parallaxCorrectNormal( reflectVec, envMapSize, envMapPosition );
#endif
`;
function boxProjectedEnvMap(shader, envMapPosition, envMapSize) {
	shader.defines.BOX_PROJECTED_ENV_MAP = true;
	shader.uniforms.envMapPosition = { value: envMapPosition };
	shader.uniforms.envMapSize = { value: envMapSize };
	shader.vertexShader = `
  varying vec3 vWorldPosition;
  ${shader.vertexShader.replace("#include ", worldposReplace)}`;
	shader.fragmentShader = `
    ${boxProjectDefinitions}
    ${shader.fragmentShader.replace("#include ", ShaderChunk.envmap_physical_pars_fragment).replace("vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );", `vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );
         ${getIBLIrradiance_patch}
         `).replace("reflectVec = inverseTransformDirection( reflectVec, viewMatrix );", `reflectVec = inverseTransformDirection( reflectVec, viewMatrix );
         ${getIBLRadiance_patch}
        `)}`;
}
function useBoxProjectedEnv(position = new Vector3(), size = new Vector3()) {
	const [config] = import_react.useState(() => ({
		position: new Vector3(),
		size: new Vector3()
	}));
	applyProps(config, {
		position,
		size
	});
	const ref = import_react.useRef(null);
	const spread = import_react.useMemo(() => ({
		ref,
		onBeforeCompile: (shader) => boxProjectedEnvMap(shader, config.position, config.size),
		customProgramCacheKey: () => JSON.stringify(config.position.toArray()) + JSON.stringify(config.size.toArray())
	}), [...config.position.toArray(), ...config.size.toArray()]);
	import_react.useLayoutEffect(() => void (ref.current.needsUpdate = true), [config]);
	return spread;
}
//#endregion
//#region node_modules/@react-three/drei/core/BBAnchor.js
var boundingBox = /* @__PURE__ */ new Box3();
var boundingBoxSize = /* @__PURE__ */ new Vector3();
var BBAnchor = ({ anchor, ...props }) => {
	const ref = import_react.useRef(null);
	const parentRef = import_react.useRef(null);
	import_react.useEffect(() => {
		var _ref$current;
		if ((_ref$current = ref.current) != null && (_ref$current = _ref$current.parent) != null && _ref$current.parent) {
			parentRef.current = ref.current.parent;
			ref.current.parent.parent.add(ref.current);
		}
	}, []);
	useFrame(() => {
		if (parentRef.current) {
			boundingBox.setFromObject(parentRef.current);
			boundingBox.getSize(boundingBoxSize);
			ref.current.position.set(parentRef.current.position.x + boundingBoxSize.x * (Array.isArray(anchor) ? anchor[0] : anchor.x) / 2, parentRef.current.position.y + boundingBoxSize.y * (Array.isArray(anchor) ? anchor[1] : anchor.y) / 2, parentRef.current.position.z + boundingBoxSize.z * (Array.isArray(anchor) ? anchor[2] : anchor.z) / 2);
		}
	});
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props));
};
//#endregion
//#region node_modules/@react-three/drei/core/TrailTexture.js
function smoothAverage(current, measurement, smoothing = .9) {
	return measurement * smoothing + current * (1 - smoothing);
}
var easeCircleOut = (x) => Math.sqrt(1 - Math.pow(x - 1, 2));
var TrailTextureImpl = class {
	constructor({ size = 256, maxAge = 750, radius = .3, intensity = .2, interpolate = 0, smoothing = 0, minForce = .3, blend = "screen", ease = easeCircleOut } = {}) {
		this.size = size;
		this.maxAge = maxAge;
		this.radius = radius;
		this.intensity = intensity;
		this.ease = ease;
		this.interpolate = interpolate;
		this.smoothing = smoothing;
		this.minForce = minForce;
		this.blend = blend;
		this.trail = [];
		this.force = 0;
		this.initTexture();
	}
	initTexture() {
		this.canvas = document.createElement("canvas");
		this.canvas.width = this.canvas.height = this.size;
		const ctx = this.canvas.getContext("2d");
		if (ctx === null) throw new Error("2D not available");
		this.ctx = ctx;
		this.ctx.fillStyle = "black";
		this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
		this.texture = new Texture$1(this.canvas);
		this.canvas.id = "touchTexture";
		this.canvas.style.width = this.canvas.style.height = `${this.canvas.width}px`;
	}
	update(delta) {
		this.clear();
		this.trail.forEach((point, i) => {
			point.age += delta * 1e3;
			if (point.age > this.maxAge) this.trail.splice(i, 1);
		});
		if (!this.trail.length) this.force = 0;
		this.trail.forEach((point) => {
			this.drawTouch(point);
		});
		this.texture.needsUpdate = true;
	}
	clear() {
		this.ctx.globalCompositeOperation = "source-over";
		this.ctx.fillStyle = "black";
		this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
	}
	addTouch(point) {
		const last = this.trail[this.trail.length - 1];
		if (last) {
			const dx = last.x - point.x;
			const dy = last.y - point.y;
			const dd = dx * dx + dy * dy;
			const force = Math.max(this.minForce, Math.min(dd * 1e4, 1));
			this.force = smoothAverage(force, this.force, this.smoothing);
			if (!!this.interpolate) {
				const lines = Math.ceil(dd / Math.pow(this.radius * .5 / this.interpolate, 2));
				if (lines > 1) for (let i = 1; i < lines; i++) this.trail.push({
					x: last.x - dx / lines * i,
					y: last.y - dy / lines * i,
					age: 0,
					force
				});
			}
		}
		this.trail.push({
			x: point.x,
			y: point.y,
			age: 0,
			force: this.force
		});
	}
	drawTouch(point) {
		const pos = {
			x: point.x * this.size,
			y: (1 - point.y) * this.size
		};
		let intensity = 1;
		if (point.age < this.maxAge * .3) intensity = this.ease(point.age / (this.maxAge * .3));
		else intensity = this.ease(1 - (point.age - this.maxAge * .3) / (this.maxAge * .7));
		intensity *= point.force;
		this.ctx.globalCompositeOperation = this.blend;
		const radius = this.size * this.radius * intensity;
		const grd = this.ctx.createRadialGradient(pos.x, pos.y, Math.max(0, radius * .25), pos.x, pos.y, Math.max(0, radius));
		grd.addColorStop(0, `rgba(255, 255, 255, ${this.intensity})`);
		grd.addColorStop(1, `rgba(0, 0, 0, 0.0)`);
		this.ctx.beginPath();
		this.ctx.fillStyle = grd;
		this.ctx.arc(pos.x, pos.y, Math.max(0, radius), 0, Math.PI * 2);
		this.ctx.fill();
	}
};
function useTrailTexture(config = {}) {
	const { size, maxAge, radius, intensity, interpolate, smoothing, minForce, blend, ease } = config;
	const trail = (0, import_react.useMemo)(() => new TrailTextureImpl(config), [
		size,
		maxAge,
		radius,
		intensity,
		interpolate,
		smoothing,
		minForce,
		blend,
		ease
	]);
	useFrame((_, delta) => void trail.update(delta));
	const onMove = (0, import_react.useCallback)((e) => trail.addTouch(e.uv), [trail]);
	return [trail.texture, onMove];
}
var TrailTexture = ({ children, ...config }) => {
	const ret = useTrailTexture(config);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(ret));
};
//#endregion
//#region node_modules/@react-three/drei/core/Center.js
var Center = /* @__PURE__ */ import_react.forwardRef(function Center({ children, object, disable, disableX, disableY, disableZ, left, right, top, bottom, front, back, onCentered, precise = true, cacheKey = 0, ...props }, fRef) {
	const ref = import_react.useRef(null);
	const outer = import_react.useRef(null);
	const inner = import_react.useRef(null);
	const [box3] = import_react.useState(() => new Box3());
	const [center] = import_react.useState(() => new Vector3());
	const [sphere] = import_react.useState(() => new Sphere$1());
	import_react.useLayoutEffect(() => {
		outer.current.matrixWorld.identity();
		box3.setFromObject(object !== null && object !== void 0 ? object : inner.current, precise);
		const width = box3.max.x - box3.min.x;
		const height = box3.max.y - box3.min.y;
		const depth = box3.max.z - box3.min.z;
		box3.getCenter(center);
		box3.getBoundingSphere(sphere);
		const vAlign = top ? height / 2 : bottom ? -height / 2 : 0;
		const hAlign = left ? -width / 2 : right ? width / 2 : 0;
		const dAlign = front ? depth / 2 : back ? -depth / 2 : 0;
		outer.current.position.set(disable || disableX ? 0 : -center.x + hAlign, disable || disableY ? 0 : -center.y + vAlign, disable || disableZ ? 0 : -center.z + dAlign);
		onCentered?.({
			parent: ref.current.parent,
			container: ref.current,
			width,
			height,
			depth,
			boundingBox: box3,
			boundingSphere: sphere,
			center,
			verticalAlignment: vAlign,
			horizontalAlignment: hAlign,
			depthAlignment: dAlign
		});
	}, [
		cacheKey,
		onCentered,
		top,
		left,
		front,
		disable,
		disableX,
		disableY,
		disableZ,
		object,
		precise,
		right,
		bottom,
		back,
		box3,
		center,
		sphere
	]);
	import_react.useImperativeHandle(fRef, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement("group", { ref: outer }, /*#__PURE__*/ import_react.createElement("group", { ref: inner }, children)));
});
//#endregion
//#region node_modules/@react-three/drei/core/Example.js
/**
* A simple counter example component. Click to increment, meta-click to decrement.
*/
var Example = /* @__PURE__ */ import_react.forwardRef(({ font, color = "#cbcbcb", bevelSize = .04, debug = false, children, ...props }, fref) => {
	const [counter, setCounter] = import_react.useState(0);
	const incr = import_react.useCallback((x = 1) => setCounter(counter + x), [counter]);
	const decr = import_react.useCallback((x = 1) => setCounter(counter - x), [counter]);
	const api = import_react.useMemo(() => ({
		incr,
		decr
	}), [incr, decr]);
	import_react.useImperativeHandle(fref, () => api, [api]);
	return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement(import_react.Suspense, { fallback: null }, /*#__PURE__*/ import_react.createElement(Center, {
		top: true,
		cacheKey: JSON.stringify({
			counter,
			font
		})
	}, /*#__PURE__*/ import_react.createElement(Text3D, {
		bevelEnabled: true,
		bevelSize,
		font
	}, debug ? /*#__PURE__*/ import_react.createElement("meshNormalMaterial", { wireframe: true }) : /*#__PURE__*/ import_react.createElement("meshStandardMaterial", { color }), counter))), children);
});
//#endregion
//#region node_modules/@react-three/drei/helpers/deprecated.js
/**
* Sets `BufferAttribute.updateRange` since r159.
*/
var setUpdateRange = (attribute, updateRange) => {
	attribute.updateRanges[0] = updateRange;
};
//#endregion
//#region node_modules/@react-three/drei/core/Instances.js
function isFunctionChild(value) {
	return typeof value === "function";
}
var _instanceLocalMatrix = /* @__PURE__ */ new Matrix4();
var _instanceWorldMatrix = /* @__PURE__ */ new Matrix4();
var _instanceIntersects = [];
var _mesh = /* @__PURE__ */ new Mesh();
var PositionMesh = class extends Group {
	constructor() {
		super();
		this.color = new Color("white");
		this.instance = { current: void 0 };
		this.instanceKey = { current: void 0 };
	}
	get geometry() {
		var _this$instance$curren;
		return (_this$instance$curren = this.instance.current) == null ? void 0 : _this$instance$curren.geometry;
	}
	raycast(raycaster, intersects) {
		const parent = this.instance.current;
		if (!parent) return;
		if (!parent.geometry || !parent.material) return;
		_mesh.geometry = parent.geometry;
		const matrixWorld = parent.matrixWorld;
		const instanceId = parent.userData.instances.indexOf(this.instanceKey);
		if (instanceId === -1 || instanceId > parent.count) return;
		parent.getMatrixAt(instanceId, _instanceLocalMatrix);
		_instanceWorldMatrix.multiplyMatrices(matrixWorld, _instanceLocalMatrix);
		_mesh.matrixWorld = _instanceWorldMatrix;
		if (parent.material instanceof Material) _mesh.material.side = parent.material.side;
		else _mesh.material.side = parent.material[0].side;
		_mesh.raycast(raycaster, _instanceIntersects);
		for (let i = 0, l = _instanceIntersects.length; i < l; i++) {
			const intersect = _instanceIntersects[i];
			intersect.instanceId = instanceId;
			intersect.object = this;
			intersects.push(intersect);
		}
		_instanceIntersects.length = 0;
	}
};
var globalContext = /* @__PURE__ */ import_react.createContext(null);
var parentMatrix$2 = /* @__PURE__ */ new Matrix4();
var instanceMatrix = /* @__PURE__ */ new Matrix4();
var tempMatrix = /* @__PURE__ */ new Matrix4();
var translation$1 = /* @__PURE__ */ new Vector3();
var rotation$1 = /* @__PURE__ */ new Quaternion();
var scale$1 = /* @__PURE__ */ new Vector3();
var isInstancedBufferAttribute = (attr) => attr.isInstancedBufferAttribute;
var Instance = /* @__PURE__ */ import_react.forwardRef(({ context, children, ...props }, ref) => {
	import_react.useMemo(() => extend({ PositionMesh }), []);
	const group = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => group.current, []);
	const { subscribe, getParent } = import_react.useContext(context || globalContext);
	import_react.useLayoutEffect(() => subscribe(group), []);
	return /*#__PURE__*/ import_react.createElement("positionMesh", _extends$1({
		instance: getParent(),
		instanceKey: group,
		ref: group
	}, props), children);
});
var Instances = /* @__PURE__ */ import_react.forwardRef(({ context, children, range, limit = 1e3, frames = Infinity, ...props }, ref) => {
	const [{ localContext, instance }] = import_react.useState(() => {
		const localContext = /*#__PURE__*/ import_react.createContext(null);
		return {
			localContext,
			instance: /*#__PURE__*/ import_react.forwardRef((props, ref) => /*#__PURE__*/ import_react.createElement(Instance, _extends$1({ context: localContext }, props, { ref })))
		};
	});
	const parentRef = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => parentRef.current, []);
	const [instances, setInstances] = import_react.useState([]);
	const [[matrices, colors]] = import_react.useState(() => {
		const mArray = new Float32Array(limit * 16);
		for (let i = 0; i < limit; i++) tempMatrix.identity().toArray(mArray, i * 16);
		return [mArray, new Float32Array([...new Array(limit * 3)].map(() => 1))];
	});
	import_react.useEffect(() => {
		parentRef.current.instanceMatrix.needsUpdate = true;
	});
	let iterations = 0;
	let count = 0;
	const attributes = import_react.useRef([]);
	import_react.useLayoutEffect(() => {
		attributes.current = Object.entries(parentRef.current.geometry.attributes).filter(([_name, value]) => isInstancedBufferAttribute(value));
	});
	useFrame(() => {
		if (frames === Infinity || iterations < frames) {
			parentRef.current.updateMatrix();
			parentRef.current.updateMatrixWorld();
			parentMatrix$2.copy(parentRef.current.matrixWorld).invert();
			count = Math.min(limit, range !== void 0 ? range : limit, instances.length);
			parentRef.current.count = count;
			setUpdateRange(parentRef.current.instanceMatrix, {
				start: 0,
				count: count * 16
			});
			setUpdateRange(parentRef.current.instanceColor, {
				start: 0,
				count: count * 3
			});
			for (let i = 0; i < instances.length; i++) {
				const instance = instances[i].current;
				instance.matrixWorld.decompose(translation$1, rotation$1, scale$1);
				instanceMatrix.compose(translation$1, rotation$1, scale$1).premultiply(parentMatrix$2);
				instanceMatrix.toArray(matrices, i * 16);
				parentRef.current.instanceMatrix.needsUpdate = true;
				instance.color.toArray(colors, i * 3);
				parentRef.current.instanceColor.needsUpdate = true;
			}
			iterations++;
		}
	});
	const api = import_react.useMemo(() => ({
		getParent: () => parentRef,
		subscribe: (ref) => {
			setInstances((instances) => [...instances, ref]);
			return () => setInstances((instances) => instances.filter((item) => item.current !== ref.current));
		}
	}), []);
	return /*#__PURE__*/ import_react.createElement("instancedMesh", _extends$1({
		userData: {
			instances,
			limit,
			frames
		},
		matrixAutoUpdate: false,
		ref: parentRef,
		args: [
			null,
			null,
			0
		],
		raycast: () => null
	}, props), /*#__PURE__*/ import_react.createElement("instancedBufferAttribute", {
		attach: "instanceMatrix",
		args: [matrices, 16],
		usage: DynamicDrawUsage
	}), /*#__PURE__*/ import_react.createElement("instancedBufferAttribute", {
		attach: "instanceColor",
		args: [colors, 3],
		usage: DynamicDrawUsage
	}), isFunctionChild(children) ? /*#__PURE__*/ import_react.createElement(localContext.Provider, { value: api }, children(instance)) : context ? /*#__PURE__*/ import_react.createElement(context.Provider, { value: api }, children) : /*#__PURE__*/ import_react.createElement(globalContext.Provider, { value: api }, children));
});
var Merged = /* @__PURE__ */ import_react.forwardRef(function Merged({ meshes, children, ...props }, ref) {
	const isArray = Array.isArray(meshes);
	if (!isArray) {
		for (const key of Object.keys(meshes)) if (!meshes[key].isMesh) delete meshes[key];
	}
	const render = (args) => isArray ? children(...args) : children(Object.keys(meshes).filter((key) => meshes[key].isMesh).reduce((acc, key, i) => ({
		...acc,
		[key]: args[i]
	}), {}));
	const components = (isArray ? meshes : Object.values(meshes)).map(({ geometry, material }) => /*#__PURE__*/ import_react.createElement(Instances, _extends$1({
		key: geometry.uuid,
		geometry,
		material
	}, props)));
	return /*#__PURE__*/ import_react.createElement("group", { ref }, renderRecursive(render, components));
});
function renderRecursive(render, components, results = []) {
	if (!components[0]) return render(results);
	function nextRender(value) {
		return renderRecursive(render, components.slice(1), results.concat([value]));
	}
	return typeof components[0] === "function" ? components[0]({
		results,
		render: nextRender
	}) : /*#__PURE__*/ import_react.cloneElement(components[0], { children: nextRender });
}
/** Idea and implementation for global instances and instanced attributes by
/*  Matias Gonzalez Fernandez https://x.com/matiNotFound
/*  and Paul Henschel https://x.com/0xca0a
*/
function createInstances() {
	const context = /*#__PURE__*/ import_react.createContext(null);
	return [/*#__PURE__*/ import_react.forwardRef((props, fref) => /*#__PURE__*/ import_react.createElement(Instances, _extends$1({
		ref: fref,
		context
	}, props))), /*#__PURE__*/ import_react.forwardRef((props, fref) => /*#__PURE__*/ import_react.createElement(Instance, _extends$1({
		ref: fref,
		context
	}, props)))];
}
var InstancedAttribute = /*#__PURE__*/ import_react.forwardRef(({ name, defaultValue, normalized, usage = DynamicDrawUsage }, fref) => {
	const ref = import_react.useRef(null);
	import_react.useImperativeHandle(fref, () => ref.current, []);
	import_react.useLayoutEffect(() => {
		const parent = ref.current.__r3f.parent.object;
		parent.geometry.attributes[name] = ref.current;
		const value = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
		const array = Array.from({ length: parent.userData.limit }, () => value).flat();
		ref.current.array = new Float32Array(array);
		ref.current.itemSize = value.length;
		ref.current.count = array.length / ref.current.itemSize;
		return () => {
			delete parent.geometry.attributes[name];
		};
	}, [name]);
	let iterations = 0;
	useFrame(() => {
		const parent = ref.current.__r3f.parent.object;
		if (parent.userData.frames === Infinity || iterations < parent.userData.frames) {
			for (let i = 0; i < parent.userData.instances.length; i++) {
				const value = parent.userData.instances[i].current[name];
				if (value !== void 0) {
					ref.current.set(Array.isArray(value) ? value : typeof value.toArray === "function" ? value.toArray() : [value], i * ref.current.itemSize);
					ref.current.needsUpdate = true;
				}
			}
			iterations++;
		}
	});
	return /*#__PURE__*/ import_react.createElement("instancedBufferAttribute", {
		ref,
		usage,
		normalized
	});
});
//#endregion
//#region node_modules/@react-three/drei/core/SpriteAnimator.js
var context$6 = /*#__PURE__*/ import_react.createContext(null);
function useSpriteAnimator() {
	return import_react.useContext(context$6);
}
function isSpriteData(data) {
	return data !== null && "meta" in data && "frames" in data;
}
var geometry = /* @__PURE__ */ new PlaneGeometry(1, 1);
var SpriteAnimator = /* @__PURE__ */ import_react.forwardRef(({ startFrame = 0, endFrame, fps = 30, frameName = "", textureDataURL, textureImageURL, loop = false, numberOfFrames = 1, autoPlay = true, animationNames, onStart, onEnd, onLoopEnd, onFrame, play, pause = false, flipX = false, alphaTest = 0, children, asSprite = false, offset, playBackwards = false, resetOnEnd = false, maxItems = 1, instanceItems = [[
	0,
	0,
	0
]], spriteDataset, canvasRenderingContext2DSettings, roundFramePosition = false, meshProps = {}, ...props }, fref) => {
	const ref = import_react.useRef(new Group());
	const spriteData = import_react.useRef(null);
	const matRef = import_react.useRef(null);
	const spriteRef = import_react.useRef(null);
	const timerOffset = import_react.useRef(window.performance.now());
	const currentFrame = import_react.useRef(startFrame);
	const currentFrameName = import_react.useRef(frameName);
	const fpsInterval = fps > 0 ? 1e3 / fps : 0;
	const [spriteTexture, setSpriteTexture] = import_react.useState(new Texture$1());
	const totalFrames = import_react.useRef(0);
	const [aspect, setAspect] = import_react.useState(new Vector3(1, 1, 1));
	const flipOffset = flipX ? -1 : 1;
	const pauseRef = import_react.useRef(pause);
	const pos = import_react.useRef(offset);
	const softEnd = import_react.useRef(false);
	const { spriteObj, loadJsonAndTexture } = useSpriteLoader(null, null, animationNames, numberOfFrames, void 0, canvasRenderingContext2DSettings);
	const frameNameRef = import_react.useRef(frameName);
	const parseSpriteDataLite = import_react.useCallback((textureData, data) => {
		if (data === null) {
			if (numberOfFrames) {
				totalFrames.current = numberOfFrames;
				if (playBackwards) currentFrame.current = numberOfFrames - 1;
				spriteData.current = data;
			}
		} else {
			var _spriteData$current$f, _spriteData$current;
			spriteData.current = data;
			if (spriteData.current && Array.isArray(spriteData.current.frames)) totalFrames.current = spriteData.current.frames.length;
			else if (spriteData.current && typeof spriteData.current === "object" && frameNameRef.current) totalFrames.current = spriteData.current.frames[frameNameRef.current].length;
			else totalFrames.current = 0;
			if (playBackwards) currentFrame.current = totalFrames.current - 1;
			const { w, h } = getFirstFrame((_spriteData$current$f = (_spriteData$current = spriteData.current) == null ? void 0 : _spriteData$current.frames) !== null && _spriteData$current$f !== void 0 ? _spriteData$current$f : [], frameNameRef.current).sourceSize;
			setAspect(calculateAspectRatio(w, h));
			if (matRef.current) matRef.current.map = textureData;
		}
		setSpriteTexture(textureData);
	}, [numberOfFrames, playBackwards]);
	const modifySpritePosition = import_react.useCallback(() => {
		if (!spriteData.current) return;
		const { meta: { size: metaInfo }, frames } = spriteData.current;
		const { w: frameW, h: frameH } = Array.isArray(frames) ? frames[0].sourceSize : frameName ? frames[frameName] ? frames[frameName][0].sourceSize : {
			w: 0,
			h: 0
		} : {
			w: 0,
			h: 0
		};
		if (matRef.current && matRef.current.map) {
			matRef.current.map.wrapS = matRef.current.map.wrapT = RepeatWrapping;
			matRef.current.map.center.set(0, 0);
			matRef.current.map.repeat.set(1 * flipOffset / (metaInfo.w / frameW), 1 / (metaInfo.h / frameH));
		}
		const frameOffsetY = 1 / ((metaInfo.h - 1) / frameH);
		if (matRef.current && matRef.current.map) {
			matRef.current.map.offset.x = 0;
			matRef.current.map.offset.y = 1 - frameOffsetY;
		}
		if (onStart) onStart({
			currentFrameName: frameName !== null && frameName !== void 0 ? frameName : "",
			currentFrame: currentFrame.current
		});
	}, [
		flipOffset,
		frameName,
		onStart
	]);
	const state = import_react.useMemo(() => ({
		current: pos.current,
		offset: pos.current,
		imageUrl: textureImageURL,
		hasEnded: false,
		ref: fref
	}), [textureImageURL, fref]);
	import_react.useImperativeHandle(fref, () => ref.current, []);
	import_react.useLayoutEffect(() => {
		pos.current = offset;
	}, [offset]);
	const calculateAspectRatio = (width, height) => {
		var _spriteRef$current;
		const ret = new Vector3();
		const aspectRatio = height / width;
		ret.set(1, aspectRatio, 1);
		(_spriteRef$current = spriteRef.current) == null || _spriteRef$current.scale.copy(ret);
		return ret;
	};
	import_react.useEffect(() => {
		if (spriteDataset) {
			var _spriteDataset$sprite;
			parseSpriteDataLite(spriteDataset == null || (_spriteDataset$sprite = spriteDataset.spriteTexture) == null ? void 0 : _spriteDataset$sprite.clone(), spriteDataset.spriteData);
		} else if (textureImageURL && textureDataURL) loadJsonAndTexture(textureImageURL, textureDataURL);
	}, [
		loadJsonAndTexture,
		spriteDataset,
		textureDataURL,
		textureImageURL,
		parseSpriteDataLite
	]);
	import_react.useEffect(() => {
		if (spriteObj) {
			var _spriteObj$spriteText;
			parseSpriteDataLite(spriteObj == null || (_spriteObj$spriteText = spriteObj.spriteTexture) == null ? void 0 : _spriteObj$spriteText.clone(), spriteObj == null ? void 0 : spriteObj.spriteData);
		}
	}, [spriteObj, parseSpriteDataLite]);
	import_react.useEffect(() => {
		state.hasEnded = false;
		if (spriteData.current && playBackwards === true) {
			var _ref;
			currentFrame.current = ((_ref = spriteData.current.frames.length) !== null && _ref !== void 0 ? _ref : 0) - 1;
		} else currentFrame.current = 0;
	}, [playBackwards, state]);
	import_react.useLayoutEffect(() => {
		modifySpritePosition();
	}, [
		spriteTexture,
		flipX,
		modifySpritePosition
	]);
	import_react.useEffect(() => {
		if (autoPlay) pauseRef.current = false;
	}, [autoPlay]);
	import_react.useLayoutEffect(() => {
		if (currentFrameName.current !== frameName && frameName) {
			currentFrame.current = 0;
			currentFrameName.current = frameName;
			state.hasEnded = false;
			if (fpsInterval <= 0) currentFrame.current = endFrame || startFrame || 0;
			if (spriteData.current) {
				const { w, h } = getFirstFrame(spriteData.current.frames, frameName).sourceSize;
				setAspect(calculateAspectRatio(w, h));
			}
		}
	}, [
		frameName,
		fpsInterval,
		state,
		endFrame,
		startFrame
	]);
	const runAnimation = () => {
		if (!isSpriteData(spriteData.current)) return;
		const { meta: { size: metaInfo }, frames } = spriteData.current;
		const { w: frameW, h: frameH } = getFirstFrame(frames, frameName).sourceSize;
		const spriteFrames = Array.isArray(frames) ? frames : frameName ? frames[frameName] : [];
		const _endFrame = endFrame || spriteFrames.length - 1;
		var _offset = offset === void 0 ? state.current : offset;
		if (fpsInterval <= 0) {
			currentFrame.current = endFrame || startFrame || 0;
			calculateFinalPosition(frameW, frameH, metaInfo, spriteFrames);
			return;
		}
		const now = window.performance.now();
		const diff = now - timerOffset.current;
		if (diff <= fpsInterval) return;
		var endCondition = playBackwards ? currentFrame.current < 0 : currentFrame.current > _endFrame;
		var onStartCondition = playBackwards ? currentFrame.current === _endFrame : currentFrame.current === 0;
		var manualProgressEndCondition = playBackwards ? currentFrame.current < 0 : currentFrame.current >= _endFrame;
		if (endCondition) {
			currentFrame.current = loop ? startFrame !== null && startFrame !== void 0 ? startFrame : 0 : 0;
			if (playBackwards) currentFrame.current = _endFrame;
			if (loop) onLoopEnd?.({
				currentFrameName: frameName !== null && frameName !== void 0 ? frameName : "",
				currentFrame: currentFrame.current
			});
			else {
				onEnd?.({
					currentFrameName: frameName !== null && frameName !== void 0 ? frameName : "",
					currentFrame: currentFrame.current
				});
				state.hasEnded = !resetOnEnd;
				if (resetOnEnd) pauseRef.current = true;
			}
			if (!loop) return;
		} else if (onStartCondition) onStart?.({
			currentFrameName: frameName !== null && frameName !== void 0 ? frameName : "",
			currentFrame: currentFrame.current
		});
		if (_offset !== void 0 && manualProgressEndCondition) {
			if (softEnd.current === false) {
				onEnd?.({
					currentFrameName: frameName !== null && frameName !== void 0 ? frameName : "",
					currentFrame: currentFrame.current
				});
				softEnd.current = true;
			}
		} else softEnd.current = false;
		if (diff <= fpsInterval) return;
		timerOffset.current = now - diff % fpsInterval;
		calculateFinalPosition(frameW, frameH, metaInfo, spriteFrames);
	};
	const calculateFinalPosition = (frameW, frameH, metaInfo, spriteFrames) => {
		var _offset = offset === void 0 ? state.current : offset;
		const targetFrame = currentFrame.current;
		let finalValX = 0;
		let finalValY = 0;
		calculateAspectRatio(frameW, frameH);
		const framesH = roundFramePosition ? Math.round((metaInfo.w - 1) / frameW) : (metaInfo.w - 1) / frameW;
		const framesV = roundFramePosition ? Math.round((metaInfo.h - 1) / frameH) : (metaInfo.h - 1) / frameH;
		if (!spriteFrames[targetFrame]) return;
		const { frame: { x: frameX, y: frameY }, sourceSize: { w: originalSizeX, h: originalSizeY } } = spriteFrames[targetFrame];
		const frameOffsetX = 1 / framesH;
		const frameOffsetY = 1 / framesV;
		if (matRef.current && matRef.current.map) {
			finalValX = flipOffset > 0 ? frameOffsetX * (frameX / originalSizeX) : frameOffsetX * (frameX / originalSizeX) - matRef.current.map.repeat.x;
			finalValY = Math.abs(1 - frameOffsetY) - frameOffsetY * (frameY / originalSizeY);
			matRef.current.map.offset.x = finalValX;
			matRef.current.map.offset.y = finalValY;
		}
		if (_offset !== void 0 && _offset !== null) {
			let frameIndex = Math.floor(_offset * spriteFrames.length);
			frameIndex = Math.max(0, Math.min(frameIndex, spriteFrames.length - 1));
			if (isNaN(frameIndex)) frameIndex = 0;
			currentFrame.current = frameIndex;
		} else if (playBackwards) currentFrame.current -= 1;
		else currentFrame.current += 1;
	};
	useFrame((_state, _delta) => {
		var _spriteData$current2, _matRef$current;
		if (!((_spriteData$current2 = spriteData.current) != null && _spriteData$current2.frames) || !((_matRef$current = matRef.current) != null && _matRef$current.map)) return;
		if (pauseRef.current) return;
		if (!state.hasEnded && (autoPlay || play)) {
			runAnimation();
			onFrame?.({
				currentFrameName: currentFrameName.current,
				currentFrame: currentFrame.current
			});
		}
	});
	function multiplyScale(initialScale = new Vector3(1, 1, 1), newScale = 1) {
		if (typeof newScale === "number") return initialScale.multiplyScalar(newScale);
		if (Array.isArray(newScale)) return initialScale.multiply(new Vector3(...newScale));
		if (newScale instanceof Vector3) return initialScale.multiply(newScale);
	}
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({}, props, {
		ref,
		scale: multiplyScale(aspect, props.scale)
	}), /*#__PURE__*/ import_react.createElement(context$6.Provider, { value: state }, asSprite && /*#__PURE__*/ import_react.createElement(Billboard, null, /*#__PURE__*/ import_react.createElement("mesh", _extends$1({
		ref: spriteRef,
		scale: 1,
		geometry
	}, meshProps), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		premultipliedAlpha: false,
		toneMapped: false,
		side: 2,
		ref: matRef,
		map: spriteTexture,
		transparent: true,
		alphaTest: alphaTest !== null && alphaTest !== void 0 ? alphaTest : 0
	}))), !asSprite && /*#__PURE__*/ import_react.createElement(Instances, _extends$1({
		geometry,
		limit: maxItems !== null && maxItems !== void 0 ? maxItems : 1
	}, meshProps), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		premultipliedAlpha: false,
		toneMapped: false,
		side: 2,
		ref: matRef,
		map: spriteTexture,
		transparent: true,
		alphaTest: alphaTest !== null && alphaTest !== void 0 ? alphaTest : 0
	}), (instanceItems !== null && instanceItems !== void 0 ? instanceItems : [0]).map((item, index) => /*#__PURE__*/ import_react.createElement(Instance, _extends$1({
		key: index,
		ref: (instanceItems == null ? void 0 : instanceItems.length) === 1 ? spriteRef : null,
		position: item,
		scale: 1
	}, meshProps)))), children));
});
//#endregion
//#region node_modules/@react-three/drei/core/CurveModifier.js
var CurveModifier = /* @__PURE__ */ import_react.forwardRef(({ children, curve }, ref) => {
	const [scene] = import_react.useState(() => new Scene());
	const [obj, set] = import_react.useState();
	const modifier = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		modifier.current = new Flow(scene.children[0]);
		set(modifier.current.object3D);
	}, [children]);
	import_react.useEffect(() => {
		var _modifier$current;
		if (curve) (_modifier$current = modifier.current) == null || _modifier$current.updateCurve(0, curve);
	}, [curve]);
	import_react.useImperativeHandle(ref, () => modifier.current);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, createPortal(children, scene), obj && /*#__PURE__*/ import_react.createElement("primitive", { object: obj }));
});
//#endregion
//#region node_modules/@react-three/drei/helpers/glsl/distort.vert.glsl.js
var distort = "#define GLSLIFY 1\nvec3 mod289(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 mod289(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 permute(vec4 x){return mod289(((x*34.0)+1.0)*x);}vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}float snoise(vec3 v){const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D=vec4(0.0,0.5,1.0,2.0);vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);vec3 g=step(x0.yzx,x0.xyz);vec3 l=1.0-g;vec3 i1=min(g.xyz,l.zxy);vec3 i2=max(g.xyz,l.zxy);vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D.yyy;i=mod289(i);vec4 p=permute(permute(permute(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));float n_=0.142857142857;vec3 ns=n_*D.wyz-D.xzx;vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;vec4 sh=-step(h,vec4(0.0));vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;vec3 p0=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1.xy,h.z);vec3 p3=vec3(a1.zw,h.w);vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));p0*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;return 42.0*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));}";
//#endregion
//#region node_modules/@react-three/drei/core/MeshDistortMaterial.js
var DistortMaterialImpl = class extends MeshPhysicalMaterial {
	constructor(parameters = {}) {
		super(parameters);
		this.setValues(parameters);
		this._time = { value: 0 };
		this._distort = { value: .4 };
		this._radius = { value: 1 };
	}
	onBeforeCompile(shader) {
		shader.uniforms.time = this._time;
		shader.uniforms.radius = this._radius;
		shader.uniforms.distort = this._distort;
		shader.vertexShader = `
      uniform float time;
      uniform float radius;
      uniform float distort;
      ${distort}
      ${shader.vertexShader}
    `;
		shader.vertexShader = shader.vertexShader.replace("#include ", `
        float updateTime = time / 50.0;
        float noise = snoise(vec3(position / 2.0 + updateTime * 5.0));
        vec3 transformed = vec3(position * (noise * pow(distort, 2.0) + radius));
        `);
	}
	get time() {
		return this._time.value;
	}
	set time(v) {
		this._time.value = v;
	}
	get distort() {
		return this._distort.value;
	}
	set distort(v) {
		this._distort.value = v;
	}
	get radius() {
		return this._radius.value;
	}
	set radius(v) {
		this._radius.value = v;
	}
};
var MeshDistortMaterial = /* @__PURE__ */ import_react.forwardRef(({ speed = 1, ...props }, ref) => {
	const [material] = import_react.useState(() => new DistortMaterialImpl());
	useFrame((state) => material && (material.time = state.clock.elapsedTime * speed));
	return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({
		object: material,
		ref,
		attach: "material"
	}, props));
});
//#endregion
//#region node_modules/@react-three/drei/core/MeshWobbleMaterial.js
var WobbleMaterialImpl = class extends MeshStandardMaterial {
	constructor(parameters = {}) {
		super(parameters);
		this.setValues(parameters);
		this._time = { value: 0 };
		this._factor = { value: 1 };
	}
	onBeforeCompile(shader) {
		shader.uniforms.time = this._time;
		shader.uniforms.factor = this._factor;
		shader.vertexShader = `
      uniform float time;
      uniform float factor;
      ${shader.vertexShader}
    `;
		shader.vertexShader = shader.vertexShader.replace("#include ", `float theta = sin( time + position.y ) / 2.0 * factor;
        float c = cos( theta );
        float s = sin( theta );
        mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );
        vec3 transformed = vec3( position ) * m;
        vNormal = vNormal * m;`);
	}
	get time() {
		return this._time.value;
	}
	set time(v) {
		this._time.value = v;
	}
	get factor() {
		return this._factor.value;
	}
	set factor(v) {
		this._factor.value = v;
	}
};
var MeshWobbleMaterial = /* @__PURE__ */ import_react.forwardRef(({ speed = 1, ...props }, ref) => {
	const [material] = import_react.useState(() => new WobbleMaterialImpl());
	useFrame((state) => material && (material.time = state.clock.elapsedTime * speed));
	return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({
		object: material,
		ref,
		attach: "material"
	}, props));
});
//#endregion
//#region node_modules/@react-three/drei/materials/ConvolutionMaterial.js
var ConvolutionMaterial = class extends ShaderMaterial {
	constructor(texelSize = new Vector2()) {
		super({
			uniforms: {
				inputBuffer: new Uniform(null),
				depthBuffer: new Uniform(null),
				resolution: new Uniform(new Vector2()),
				texelSize: new Uniform(new Vector2()),
				halfTexelSize: new Uniform(new Vector2()),
				kernel: new Uniform(0),
				scale: new Uniform(1),
				cameraNear: new Uniform(0),
				cameraFar: new Uniform(1),
				minDepthThreshold: new Uniform(0),
				maxDepthThreshold: new Uniform(1),
				depthScale: new Uniform(0),
				depthToBlurRatioBias: new Uniform(.25)
			},
			fragmentShader: `#include 
        #include       
        uniform sampler2D inputBuffer;
        uniform sampler2D depthBuffer;
        uniform float cameraNear;
        uniform float cameraFar;
        uniform float minDepthThreshold;
        uniform float maxDepthThreshold;
        uniform float depthScale;
        uniform float depthToBlurRatioBias;
        varying vec2 vUv;
        varying vec2 vUv0;
        varying vec2 vUv1;
        varying vec2 vUv2;
        varying vec2 vUv3;

        void main() {
          float depthFactor = 0.0;
          
          #ifdef USE_DEPTH
            vec4 depth = texture2D(depthBuffer, vUv);
            depthFactor = smoothstep(minDepthThreshold, maxDepthThreshold, 1.0-(depth.r * depth.a));
            depthFactor *= depthScale;
            depthFactor = max(0.0, min(1.0, depthFactor + 0.25));
          #endif
          
          vec4 sum = texture2D(inputBuffer, mix(vUv0, vUv, depthFactor));
          sum += texture2D(inputBuffer, mix(vUv1, vUv, depthFactor));
          sum += texture2D(inputBuffer, mix(vUv2, vUv, depthFactor));
          sum += texture2D(inputBuffer, mix(vUv3, vUv, depthFactor));
          gl_FragColor = sum * 0.25 ;

          #include 
          #include 
          #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
        }`,
			vertexShader: `uniform vec2 texelSize;
        uniform vec2 halfTexelSize;
        uniform float kernel;
        uniform float scale;
        varying vec2 vUv;
        varying vec2 vUv0;
        varying vec2 vUv1;
        varying vec2 vUv2;
        varying vec2 vUv3;

        void main() {
          vec2 uv = position.xy * 0.5 + 0.5;
          vUv = uv;

          vec2 dUv = (texelSize * vec2(kernel) + halfTexelSize) * scale;
          vUv0 = vec2(uv.x - dUv.x, uv.y + dUv.y);
          vUv1 = vec2(uv.x + dUv.x, uv.y + dUv.y);
          vUv2 = vec2(uv.x + dUv.x, uv.y - dUv.y);
          vUv3 = vec2(uv.x - dUv.x, uv.y - dUv.y);

          gl_Position = vec4(position.xy, 1.0, 1.0);
        }`,
			blending: 0,
			depthWrite: false,
			depthTest: false
		});
		this.toneMapped = false;
		this.setTexelSize(texelSize.x, texelSize.y);
		this.kernel = new Float32Array([
			0,
			1,
			2,
			2,
			3
		]);
	}
	setTexelSize(x, y) {
		this.uniforms.texelSize.value.set(x, y);
		this.uniforms.halfTexelSize.value.set(x, y).multiplyScalar(.5);
	}
	setResolution(resolution) {
		this.uniforms.resolution.value.copy(resolution);
	}
};
//#endregion
//#region node_modules/@react-three/drei/materials/BlurPass.js
var BlurPass = class {
	constructor({ gl, resolution, width = 500, height = 500, minDepthThreshold = 0, maxDepthThreshold = 1, depthScale = 0, depthToBlurRatioBias = .25 }) {
		this.renderToScreen = false;
		this.renderTargetA = new WebGLRenderTarget(resolution, resolution, {
			minFilter: LinearFilter,
			magFilter: LinearFilter,
			stencilBuffer: false,
			depthBuffer: false,
			type: HalfFloatType
		});
		this.renderTargetB = this.renderTargetA.clone();
		this.convolutionMaterial = new ConvolutionMaterial();
		this.convolutionMaterial.setTexelSize(1 / width, 1 / height);
		this.convolutionMaterial.setResolution(new Vector2(width, height));
		this.scene = new Scene();
		this.camera = new Camera();
		this.convolutionMaterial.uniforms.minDepthThreshold.value = minDepthThreshold;
		this.convolutionMaterial.uniforms.maxDepthThreshold.value = maxDepthThreshold;
		this.convolutionMaterial.uniforms.depthScale.value = depthScale;
		this.convolutionMaterial.uniforms.depthToBlurRatioBias.value = depthToBlurRatioBias;
		this.convolutionMaterial.defines.USE_DEPTH = depthScale > 0;
		const vertices = new Float32Array([
			-1,
			-1,
			0,
			3,
			-1,
			0,
			-1,
			3,
			0
		]);
		const uvs = new Float32Array([
			0,
			0,
			2,
			0,
			0,
			2
		]);
		const geometry = new BufferGeometry();
		geometry.setAttribute("position", new BufferAttribute(vertices, 3));
		geometry.setAttribute("uv", new BufferAttribute(uvs, 2));
		this.screen = new Mesh(geometry, this.convolutionMaterial);
		this.screen.frustumCulled = false;
		this.scene.add(this.screen);
	}
	render(renderer, inputBuffer, outputBuffer) {
		const scene = this.scene;
		const camera = this.camera;
		const renderTargetA = this.renderTargetA;
		const renderTargetB = this.renderTargetB;
		let material = this.convolutionMaterial;
		let uniforms = material.uniforms;
		uniforms.depthBuffer.value = inputBuffer.depthTexture;
		const kernel = material.kernel;
		let lastRT = inputBuffer;
		let destRT;
		let i, l;
		for (i = 0, l = kernel.length - 1; i < l; ++i) {
			destRT = (i & 1) === 0 ? renderTargetA : renderTargetB;
			uniforms.kernel.value = kernel[i];
			uniforms.inputBuffer.value = lastRT.texture;
			renderer.setRenderTarget(destRT);
			renderer.render(scene, camera);
			lastRT = destRT;
		}
		uniforms.kernel.value = kernel[i];
		uniforms.inputBuffer.value = lastRT.texture;
		renderer.setRenderTarget(this.renderToScreen ? null : outputBuffer);
		renderer.render(scene, camera);
	}
};
//#endregion
//#region node_modules/@react-three/drei/materials/MeshReflectorMaterial.js
var MeshReflectorMaterial$1 = class extends MeshStandardMaterial {
	constructor(parameters = {}) {
		super(parameters);
		this._tDepth = { value: null };
		this._distortionMap = { value: null };
		this._tDiffuse = { value: null };
		this._tDiffuseBlur = { value: null };
		this._textureMatrix = { value: null };
		this._hasBlur = { value: false };
		this._mirror = { value: 0 };
		this._mixBlur = { value: 0 };
		this._blurStrength = { value: .5 };
		this._minDepthThreshold = { value: .9 };
		this._maxDepthThreshold = { value: 1 };
		this._depthScale = { value: 0 };
		this._depthToBlurRatioBias = { value: .25 };
		this._distortion = { value: 1 };
		this._mixContrast = { value: 1 };
		this.setValues(parameters);
	}
	onBeforeCompile(shader) {
		var _shader$defines;
		if (!((_shader$defines = shader.defines) != null && _shader$defines.USE_UV)) shader.defines.USE_UV = "";
		shader.uniforms.hasBlur = this._hasBlur;
		shader.uniforms.tDiffuse = this._tDiffuse;
		shader.uniforms.tDepth = this._tDepth;
		shader.uniforms.distortionMap = this._distortionMap;
		shader.uniforms.tDiffuseBlur = this._tDiffuseBlur;
		shader.uniforms.textureMatrix = this._textureMatrix;
		shader.uniforms.mirror = this._mirror;
		shader.uniforms.mixBlur = this._mixBlur;
		shader.uniforms.mixStrength = this._blurStrength;
		shader.uniforms.minDepthThreshold = this._minDepthThreshold;
		shader.uniforms.maxDepthThreshold = this._maxDepthThreshold;
		shader.uniforms.depthScale = this._depthScale;
		shader.uniforms.depthToBlurRatioBias = this._depthToBlurRatioBias;
		shader.uniforms.distortion = this._distortion;
		shader.uniforms.mixContrast = this._mixContrast;
		shader.vertexShader = `
        uniform mat4 textureMatrix;
        varying vec4 my_vUv;
      ${shader.vertexShader}`;
		shader.vertexShader = shader.vertexShader.replace("#include ", `#include 
        my_vUv = textureMatrix * vec4( position, 1.0 );
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );`);
		shader.fragmentShader = `
        uniform sampler2D tDiffuse;
        uniform sampler2D tDiffuseBlur;
        uniform sampler2D tDepth;
        uniform sampler2D distortionMap;
        uniform float distortion;
        uniform float cameraNear;
			  uniform float cameraFar;
        uniform bool hasBlur;
        uniform float mixBlur;
        uniform float mirror;
        uniform float mixStrength;
        uniform float minDepthThreshold;
        uniform float maxDepthThreshold;
        uniform float mixContrast;
        uniform float depthScale;
        uniform float depthToBlurRatioBias;
        varying vec4 my_vUv;
        ${shader.fragmentShader}`;
		shader.fragmentShader = shader.fragmentShader.replace("#include ", `#include 

      float distortionFactor = 0.0;
      #ifdef USE_DISTORTION
        distortionFactor = texture2D(distortionMap, vUv).r * distortion;
      #endif

      vec4 new_vUv = my_vUv;
      new_vUv.x += distortionFactor;
      new_vUv.y += distortionFactor;

      vec4 base = texture2DProj(tDiffuse, new_vUv);
      vec4 blur = texture2DProj(tDiffuseBlur, new_vUv);

      vec4 merge = base;

      #ifdef USE_NORMALMAP
        vec2 normal_uv = vec2(0.0);
        vec4 normalColor = texture2D(normalMap, vUv * normalScale);
        vec3 my_normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b,  normalColor.g * 2.0 - 1.0 ) );
        vec3 coord = new_vUv.xyz / new_vUv.w;
        normal_uv = coord.xy + coord.z * my_normal.xz * 0.05;
        vec4 base_normal = texture2D(tDiffuse, normal_uv);
        vec4 blur_normal = texture2D(tDiffuseBlur, normal_uv);
        merge = base_normal;
        blur = blur_normal;
      #endif

      float depthFactor = 0.0001;
      float blurFactor = 0.0;

      #ifdef USE_DEPTH
        vec4 depth = texture2DProj(tDepth, new_vUv);
        depthFactor = smoothstep(minDepthThreshold, maxDepthThreshold, 1.0-(depth.r * depth.a));
        depthFactor *= depthScale;
        depthFactor = max(0.0001, min(1.0, depthFactor));

        #ifdef USE_BLUR
          blur = blur * min(1.0, depthFactor + depthToBlurRatioBias);
          merge = merge * min(1.0, depthFactor + 0.5);
        #else
          merge = merge * depthFactor;
        #endif

      #endif

      float reflectorRoughnessFactor = roughness;
      #ifdef USE_ROUGHNESSMAP
        vec4 reflectorTexelRoughness = texture2D( roughnessMap, vUv );
        reflectorRoughnessFactor *= reflectorTexelRoughness.g;
      #endif

      #ifdef USE_BLUR
        blurFactor = min(1.0, mixBlur * reflectorRoughnessFactor);
        merge = mix(merge, blur, blurFactor);
      #endif

      vec4 newMerge = vec4(0.0, 0.0, 0.0, 1.0);
      newMerge.r = (merge.r - 0.5) * mixContrast + 0.5;
      newMerge.g = (merge.g - 0.5) * mixContrast + 0.5;
      newMerge.b = (merge.b - 0.5) * mixContrast + 0.5;

      diffuseColor.rgb = diffuseColor.rgb * ((1.0 - min(1.0, mirror)) + newMerge.rgb * mixStrength);
      `);
	}
	get tDiffuse() {
		return this._tDiffuse.value;
	}
	set tDiffuse(v) {
		this._tDiffuse.value = v;
	}
	get tDepth() {
		return this._tDepth.value;
	}
	set tDepth(v) {
		this._tDepth.value = v;
	}
	get distortionMap() {
		return this._distortionMap.value;
	}
	set distortionMap(v) {
		this._distortionMap.value = v;
	}
	get tDiffuseBlur() {
		return this._tDiffuseBlur.value;
	}
	set tDiffuseBlur(v) {
		this._tDiffuseBlur.value = v;
	}
	get textureMatrix() {
		return this._textureMatrix.value;
	}
	set textureMatrix(v) {
		this._textureMatrix.value = v;
	}
	get hasBlur() {
		return this._hasBlur.value;
	}
	set hasBlur(v) {
		this._hasBlur.value = v;
	}
	get mirror() {
		return this._mirror.value;
	}
	set mirror(v) {
		this._mirror.value = v;
	}
	get mixBlur() {
		return this._mixBlur.value;
	}
	set mixBlur(v) {
		this._mixBlur.value = v;
	}
	get mixStrength() {
		return this._blurStrength.value;
	}
	set mixStrength(v) {
		this._blurStrength.value = v;
	}
	get minDepthThreshold() {
		return this._minDepthThreshold.value;
	}
	set minDepthThreshold(v) {
		this._minDepthThreshold.value = v;
	}
	get maxDepthThreshold() {
		return this._maxDepthThreshold.value;
	}
	set maxDepthThreshold(v) {
		this._maxDepthThreshold.value = v;
	}
	get depthScale() {
		return this._depthScale.value;
	}
	set depthScale(v) {
		this._depthScale.value = v;
	}
	get depthToBlurRatioBias() {
		return this._depthToBlurRatioBias.value;
	}
	set depthToBlurRatioBias(v) {
		this._depthToBlurRatioBias.value = v;
	}
	get distortion() {
		return this._distortion.value;
	}
	set distortion(v) {
		this._distortion.value = v;
	}
	get mixContrast() {
		return this._mixContrast.value;
	}
	set mixContrast(v) {
		this._mixContrast.value = v;
	}
};
//#endregion
//#region node_modules/@react-three/drei/core/MeshReflectorMaterial.js
var MeshReflectorMaterial = /* @__PURE__ */ import_react.forwardRef(({ mixBlur = 0, mixStrength = 1, resolution = 256, blur = [0, 0], minDepthThreshold = .9, maxDepthThreshold = 1, depthScale = 0, depthToBlurRatioBias = .25, mirror = 0, distortion = 1, mixContrast = 1, distortionMap, reflectorOffset = 0, ...props }, ref) => {
	extend({ MeshReflectorMaterialImpl: MeshReflectorMaterial$1 });
	const gl = useThree(({ gl }) => gl);
	const camera = useThree(({ camera }) => camera);
	const scene = useThree(({ scene }) => scene);
	blur = Array.isArray(blur) ? blur : [blur, blur];
	const hasBlur = blur[0] + blur[1] > 0;
	const blurX = blur[0];
	const blurY = blur[1];
	const materialRef = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => materialRef.current, []);
	const [reflectorPlane] = import_react.useState(() => new Plane$1());
	const [normal] = import_react.useState(() => new Vector3());
	const [reflectorWorldPosition] = import_react.useState(() => new Vector3());
	const [cameraWorldPosition] = import_react.useState(() => new Vector3());
	const [rotationMatrix] = import_react.useState(() => new Matrix4());
	const [lookAtPosition] = import_react.useState(() => new Vector3(0, 0, -1));
	const [clipPlane] = import_react.useState(() => new Vector4());
	const [view] = import_react.useState(() => new Vector3());
	const [target] = import_react.useState(() => new Vector3());
	const [q] = import_react.useState(() => new Vector4());
	const [textureMatrix] = import_react.useState(() => new Matrix4());
	const [virtualCamera] = import_react.useState(() => new PerspectiveCamera$1());
	const beforeRender = import_react.useCallback(() => {
		var _materialRef$current;
		const parent = materialRef.current.parent || ((_materialRef$current = materialRef.current) == null || (_materialRef$current = _materialRef$current.__r3f.parent) == null ? void 0 : _materialRef$current.object);
		if (!parent) return;
		reflectorWorldPosition.setFromMatrixPosition(parent.matrixWorld);
		cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
		rotationMatrix.extractRotation(parent.matrixWorld);
		normal.set(0, 0, 1);
		normal.applyMatrix4(rotationMatrix);
		reflectorWorldPosition.addScaledVector(normal, reflectorOffset);
		view.subVectors(reflectorWorldPosition, cameraWorldPosition);
		if (view.dot(normal) > 0) return;
		view.reflect(normal).negate();
		view.add(reflectorWorldPosition);
		rotationMatrix.extractRotation(camera.matrixWorld);
		lookAtPosition.set(0, 0, -1);
		lookAtPosition.applyMatrix4(rotationMatrix);
		lookAtPosition.add(cameraWorldPosition);
		target.subVectors(reflectorWorldPosition, lookAtPosition);
		target.reflect(normal).negate();
		target.add(reflectorWorldPosition);
		virtualCamera.position.copy(view);
		virtualCamera.up.set(0, 1, 0);
		virtualCamera.up.applyMatrix4(rotationMatrix);
		virtualCamera.up.reflect(normal);
		virtualCamera.lookAt(target);
		virtualCamera.far = camera.far;
		virtualCamera.updateMatrixWorld();
		virtualCamera.projectionMatrix.copy(camera.projectionMatrix);
		textureMatrix.set(.5, 0, 0, .5, 0, .5, 0, .5, 0, 0, .5, .5, 0, 0, 0, 1);
		textureMatrix.multiply(virtualCamera.projectionMatrix);
		textureMatrix.multiply(virtualCamera.matrixWorldInverse);
		textureMatrix.multiply(parent.matrixWorld);
		reflectorPlane.setFromNormalAndCoplanarPoint(normal, reflectorWorldPosition);
		reflectorPlane.applyMatrix4(virtualCamera.matrixWorldInverse);
		clipPlane.set(reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant);
		const projectionMatrix = virtualCamera.projectionMatrix;
		q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
		q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
		q.z = -1;
		q.w = (1 + projectionMatrix.elements[10]) / projectionMatrix.elements[14];
		clipPlane.multiplyScalar(2 / clipPlane.dot(q));
		projectionMatrix.elements[2] = clipPlane.x;
		projectionMatrix.elements[6] = clipPlane.y;
		projectionMatrix.elements[10] = clipPlane.z + 1;
		projectionMatrix.elements[14] = clipPlane.w;
	}, [camera, reflectorOffset]);
	const [fbo1, fbo2, blurpass, reflectorProps] = import_react.useMemo(() => {
		const parameters = {
			minFilter: LinearFilter,
			magFilter: LinearFilter,
			type: HalfFloatType
		};
		const fbo1 = new WebGLRenderTarget(resolution, resolution, parameters);
		fbo1.depthBuffer = true;
		fbo1.depthTexture = new DepthTexture(resolution, resolution);
		fbo1.depthTexture.format = DepthFormat;
		fbo1.depthTexture.type = UnsignedShortType;
		const fbo2 = new WebGLRenderTarget(resolution, resolution, parameters);
		return [
			fbo1,
			fbo2,
			new BlurPass({
				gl,
				resolution,
				width: blurX,
				height: blurY,
				minDepthThreshold,
				maxDepthThreshold,
				depthScale,
				depthToBlurRatioBias
			}),
			{
				mirror,
				textureMatrix,
				mixBlur,
				tDiffuse: fbo1.texture,
				tDepth: fbo1.depthTexture,
				tDiffuseBlur: fbo2.texture,
				hasBlur,
				mixStrength,
				minDepthThreshold,
				maxDepthThreshold,
				depthScale,
				depthToBlurRatioBias,
				distortion,
				distortionMap,
				mixContrast,
				"defines-USE_BLUR": hasBlur ? "" : void 0,
				"defines-USE_DEPTH": depthScale > 0 ? "" : void 0,
				"defines-USE_DISTORTION": distortionMap ? "" : void 0
			}
		];
	}, [
		gl,
		blurX,
		blurY,
		textureMatrix,
		resolution,
		mirror,
		hasBlur,
		mixBlur,
		mixStrength,
		minDepthThreshold,
		maxDepthThreshold,
		depthScale,
		depthToBlurRatioBias,
		distortion,
		distortionMap,
		mixContrast
	]);
	useFrame(() => {
		var _materialRef$current2;
		const parent = materialRef.current.parent || ((_materialRef$current2 = materialRef.current) == null || (_materialRef$current2 = _materialRef$current2.__r3f.parent) == null ? void 0 : _materialRef$current2.object);
		if (!parent) return;
		parent.visible = false;
		const currentXrEnabled = gl.xr.enabled;
		const currentShadowAutoUpdate = gl.shadowMap.autoUpdate;
		beforeRender();
		gl.xr.enabled = false;
		gl.shadowMap.autoUpdate = false;
		gl.setRenderTarget(fbo1);
		gl.state.buffers.depth.setMask(true);
		if (!gl.autoClear) gl.clear();
		gl.render(scene, virtualCamera);
		if (hasBlur) blurpass.render(gl, fbo1, fbo2);
		gl.xr.enabled = currentXrEnabled;
		gl.shadowMap.autoUpdate = currentShadowAutoUpdate;
		parent.visible = true;
		gl.setRenderTarget(null);
	});
	return /*#__PURE__*/ import_react.createElement("meshReflectorMaterialImpl", _extends$1({
		attach: "material",
		key: "key" + reflectorProps["defines-USE_BLUR"] + reflectorProps["defines-USE_DEPTH"] + reflectorProps["defines-USE_DISTORTION"],
		ref: materialRef
	}, reflectorProps, props));
});
//#endregion
//#region node_modules/@react-three/drei/materials/MeshRefractionMaterial.js
var MeshRefractionMaterial$1 = /* @__PURE__ */ shaderMaterial({
	envMap: null,
	bounces: 3,
	ior: 2.4,
	correctMips: true,
	aberrationStrength: .01,
	fresnel: 0,
	bvh: /* @__PURE__ */ new MeshBVHUniformStruct(),
	color: /* @__PURE__ */ new Color("white"),
	opacity: 1,
	resolution: /* @__PURE__ */ new Vector2(),
	viewMatrixInverse: /* @__PURE__ */ new Matrix4(),
	projectionMatrixInverse: /* @__PURE__ */ new Matrix4()
}, `
  uniform mat4 viewMatrixInverse;

  varying vec3 vWorldPosition;
  varying vec3 vNormal;
  varying mat4 vModelMatrixInverse;

  #include 

  void main() {
    #include 

    vec4 transformedNormal = vec4(normal, 0.0);
    vec4 transformedPosition = vec4(position, 1.0);
    #ifdef USE_INSTANCING
      transformedNormal = instanceMatrix * transformedNormal;
      transformedPosition = instanceMatrix * transformedPosition;
    #endif

    #ifdef USE_INSTANCING
      vModelMatrixInverse = inverse(modelMatrix * instanceMatrix);
    #else
      vModelMatrixInverse = inverse(modelMatrix);
    #endif

    vWorldPosition = (modelMatrix * transformedPosition).xyz;
    vNormal = normalize((viewMatrixInverse * vec4(normalMatrix * transformedNormal.xyz, 0.0)).xyz);
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * transformedPosition;
  }`, `
  #define ENVMAP_TYPE_CUBE_UV
  precision highp isampler2D;
  precision highp usampler2D;
  varying vec3 vWorldPosition;
  varying vec3 vNormal;
  varying mat4 vModelMatrixInverse;

  #include 

  #ifdef ENVMAP_TYPE_CUBEM
    uniform samplerCube envMap;
  #else
    uniform sampler2D envMap;
  #endif

  uniform float bounces;
  ${shaderStructs}
  ${shaderIntersectFunction}
  uniform BVH bvh;
  uniform float ior;
  uniform bool correctMips;
  uniform vec2 resolution;
  uniform float fresnel;
  uniform mat4 modelMatrix;
  uniform mat4 projectionMatrixInverse;
  uniform mat4 viewMatrixInverse;
  uniform float aberrationStrength;
  uniform vec3 color;
  uniform float opacity;

  float fresnelFunc(vec3 viewDirection, vec3 worldNormal) {
    return pow( 1.0 + dot( viewDirection, worldNormal), 10.0 );
  }

  vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 normal, float ior, mat4 modelMatrixInverse) {
    vec3 rayOrigin = ro;
    vec3 rayDirection = rd;
    rayDirection = refract(rayDirection, normal, 1.0 / ior);
    rayOrigin = vWorldPosition + rayDirection * 0.001;
    rayOrigin = (modelMatrixInverse * vec4(rayOrigin, 1.0)).xyz;
    rayDirection = normalize((modelMatrixInverse * vec4(rayDirection, 0.0)).xyz);
    for(float i = 0.0; i < bounces; i++) {
      uvec4 faceIndices = uvec4( 0u );
      vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
      vec3 barycoord = vec3( 0.0 );
      float side = 1.0;
      float dist = 0.0;
      bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
      vec3 hitPos = rayOrigin + rayDirection * max(dist - 0.001, 0.0);
      vec3 tempDir = refract(rayDirection, faceNormal, ior);
      if (length(tempDir) != 0.0) {
        rayDirection = tempDir;
        break;
      }
      rayDirection = reflect(rayDirection, faceNormal);
      rayOrigin = hitPos + rayDirection * 0.01;
    }
    rayDirection = normalize((modelMatrix * vec4(rayDirection, 0.0)).xyz);
    return rayDirection;
  }

  #include 
  #include 

  #ifdef ENVMAP_TYPE_CUBEM
    vec4 textureGradient(samplerCube envMap, vec3 rayDirection, vec3 directionCamPerfect) {
      return textureGrad(envMap, rayDirection, dFdx(correctMips ? directionCamPerfect: rayDirection), dFdy(correctMips ? directionCamPerfect: rayDirection));
    }
  #else
    vec4 textureGradient(sampler2D envMap, vec3 rayDirection, vec3 directionCamPerfect) {
      vec2 uvv = equirectUv( rayDirection );
      vec2 smoothUv = equirectUv( directionCamPerfect );
      return textureGrad(envMap, uvv, dFdx(correctMips ? smoothUv : uvv), dFdy(correctMips ? smoothUv : uvv));
    }
  #endif

  void main() {
    vec2 uv = gl_FragCoord.xy / resolution;
    vec3 directionCamPerfect = (projectionMatrixInverse * vec4(uv * 2.0 - 1.0, 0.0, 1.0)).xyz;
    directionCamPerfect = (viewMatrixInverse * vec4(directionCamPerfect, 0.0)).xyz;
    directionCamPerfect = normalize(directionCamPerfect);
    vec3 normal = vNormal;
    vec3 rayOrigin = cameraPosition;
    vec3 rayDirection = normalize(vWorldPosition - cameraPosition);

    vec4 diffuseColor = vec4(color, opacity);
    #include 

    #ifdef CHROMATIC_ABERRATIONS
      vec3 rayDirectionG = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), vModelMatrixInverse);
      #ifdef FAST_CHROMA
        vec3 rayDirectionR = normalize(rayDirectionG + 1.0 * vec3(aberrationStrength / 2.0));
        vec3 rayDirectionB = normalize(rayDirectionG - 1.0 * vec3(aberrationStrength / 2.0));
      #else
        vec3 rayDirectionR = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 - aberrationStrength), 1.0), vModelMatrixInverse);
        vec3 rayDirectionB = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior * (1.0 + aberrationStrength), 1.0), vModelMatrixInverse);
      #endif
      float finalColorR = textureGradient(envMap, rayDirectionR, directionCamPerfect).r;
      float finalColorG = textureGradient(envMap, rayDirectionG, directionCamPerfect).g;
      float finalColorB = textureGradient(envMap, rayDirectionB, directionCamPerfect).b;
      diffuseColor.rgb *= vec3(finalColorR, finalColorG, finalColorB);
    #else
      rayDirection = totalInternalReflection(rayOrigin, rayDirection, normal, max(ior, 1.0), vModelMatrixInverse);
      diffuseColor.rgb *= textureGradient(envMap, rayDirection, directionCamPerfect).rgb;
    #endif

    vec3 viewDirection = normalize(vWorldPosition - cameraPosition);
    float nFresnel = fresnelFunc(viewDirection, normal) * fresnel;
    gl_FragColor = vec4(mix(diffuseColor.rgb, vec3(1.0), nFresnel), diffuseColor.a);

    #include 
    #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
  }`);
//#endregion
//#region node_modules/@react-three/drei/core/MeshRefractionMaterial.js
var isCubeTexture = (def) => def && def.isCubeTexture;
function MeshRefractionMaterial({ aberrationStrength = 0, fastChroma = true, envMap, ...props }) {
	extend({ MeshRefractionMaterial: MeshRefractionMaterial$1 });
	const material = (0, import_react.useRef)(null);
	const { size } = useThree();
	const defines = (0, import_react.useMemo)(() => {
		var _ref, _envMap$image$;
		const temp = {};
		const isCubeMap = isCubeTexture(envMap);
		const cubeSize = ((_ref = isCubeMap ? (_envMap$image$ = envMap.image[0]) == null ? void 0 : _envMap$image$.width : envMap.image.width) !== null && _ref !== void 0 ? _ref : 1024) / 4;
		const _lodMax = Math.floor(Math.log2(cubeSize));
		const _cubeSize = Math.pow(2, _lodMax);
		const width = 3 * Math.max(_cubeSize, 112);
		const height = 4 * _cubeSize;
		if (isCubeMap) temp.ENVMAP_TYPE_CUBEM = "";
		temp.CUBEUV_TEXEL_WIDTH = `${1 / width}`;
		temp.CUBEUV_TEXEL_HEIGHT = `${1 / height}`;
		temp.CUBEUV_MAX_MIP = `${_lodMax}.0`;
		if (aberrationStrength > 0) temp.CHROMATIC_ABERRATIONS = "";
		if (fastChroma) temp.FAST_CHROMA = "";
		return temp;
	}, [aberrationStrength, fastChroma]);
	(0, import_react.useLayoutEffect)(() => {
		var _material$current;
		const geometry = (_material$current = material.current) == null || (_material$current = _material$current.__r3f) == null || (_material$current = _material$current.parent) == null || (_material$current = _material$current.object) == null ? void 0 : _material$current.geometry;
		if (geometry) {
			material.current.bvh = new MeshBVHUniformStruct();
			material.current.bvh.updateFrom(new MeshBVH(geometry.clone().toNonIndexed(), { strategy: 2 }));
		}
	}, []);
	useFrame(({ camera }) => {
		material.current.viewMatrixInverse = camera.matrixWorld;
		material.current.projectionMatrixInverse = camera.projectionMatrixInverse;
	});
	return /*#__PURE__*/ import_react.createElement("meshRefractionMaterial", _extends$1({
		key: JSON.stringify(defines),
		defines,
		ref: material,
		resolution: [size.width, size.height],
		aberrationStrength,
		envMap
	}, props));
}
//#endregion
//#region node_modules/@react-three/drei/materials/DiscardMaterial.js
var DiscardMaterial = /* @__PURE__ */ shaderMaterial({}, "void main() { }", "void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); discard;  }");
//#endregion
//#region node_modules/@react-three/drei/core/MeshTransmissionMaterial.js
var MeshTransmissionMaterialImpl = class extends MeshPhysicalMaterial {
	constructor(samples = 6, transmissionSampler = false) {
		super();
		this.uniforms = {
			chromaticAberration: { value: .05 },
			transmission: { value: 0 },
			_transmission: { value: 1 },
			transmissionMap: { value: null },
			roughness: { value: 0 },
			thickness: { value: 0 },
			thicknessMap: { value: null },
			attenuationDistance: { value: Infinity },
			attenuationColor: { value: new Color("white") },
			anisotropicBlur: { value: .1 },
			time: { value: 0 },
			distortion: { value: 0 },
			distortionScale: { value: .5 },
			temporalDistortion: { value: 0 },
			buffer: { value: null }
		};
		this.onBeforeCompile = (shader) => {
			shader.uniforms = {
				...shader.uniforms,
				...this.uniforms
			};
			if (this.anisotropy > 0) shader.defines.USE_ANISOTROPY = "";
			if (transmissionSampler) shader.defines.USE_SAMPLER = "";
			else shader.defines.USE_TRANSMISSION = "";
			shader.fragmentShader = `
      uniform float chromaticAberration;         
      uniform float anisotropicBlur;      
      uniform float time;
      uniform float distortion;
      uniform float distortionScale;
      uniform float temporalDistortion;
      uniform sampler2D buffer;

      vec3 random3(vec3 c) {
        float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));
        vec3 r;
        r.z = fract(512.0*j);
        j *= .125;
        r.x = fract(512.0*j);
        j *= .125;
        r.y = fract(512.0*j);
        return r-0.5;
      }

      uint hash( uint x ) {
        x += ( x << 10u );
        x ^= ( x >>  6u );
        x += ( x <<  3u );
        x ^= ( x >> 11u );
        x += ( x << 15u );
        return x;
      }

      // Compound versions of the hashing algorithm I whipped together.
      uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y)                         ); }
      uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z)             ); }
      uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }

      // Construct a float with half-open range [0:1] using low 23 bits.
      // All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.
      float floatConstruct( uint m ) {
        const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask
        const uint ieeeOne      = 0x3F800000u; // 1.0 in IEEE binary32
        m &= ieeeMantissa;                     // Keep only mantissa bits (fractional part)
        m |= ieeeOne;                          // Add fractional part to 1.0
        float  f = uintBitsToFloat( m );       // Range [1:2]
        return f - 1.0;                        // Range [0:1]
      }

      // Pseudo-random value in half-open range [0:1].
      float randomBase( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }
      float randomBase( vec2  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
      float randomBase( vec3  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
      float randomBase( vec4  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
      float rand(float seed) {
        float result = randomBase(vec3(gl_FragCoord.xy, seed));
        return result;
      }

      const float F3 =  0.3333333;
      const float G3 =  0.1666667;

      float snoise(vec3 p) {
        vec3 s = floor(p + dot(p, vec3(F3)));
        vec3 x = p - s + dot(s, vec3(G3));
        vec3 e = step(vec3(0.0), x - x.yzx);
        vec3 i1 = e*(1.0 - e.zxy);
        vec3 i2 = 1.0 - e.zxy*(1.0 - e);
        vec3 x1 = x - i1 + G3;
        vec3 x2 = x - i2 + 2.0*G3;
        vec3 x3 = x - 1.0 + 3.0*G3;
        vec4 w, d;
        w.x = dot(x, x);
        w.y = dot(x1, x1);
        w.z = dot(x2, x2);
        w.w = dot(x3, x3);
        w = max(0.6 - w, 0.0);
        d.x = dot(random3(s), x);
        d.y = dot(random3(s + i1), x1);
        d.z = dot(random3(s + i2), x2);
        d.w = dot(random3(s + 1.0), x3);
        w *= w;
        w *= w;
        d *= w;
        return dot(d, vec4(52.0));
      }

      float snoiseFractal(vec3 m) {
        return 0.5333333* snoise(m)
              +0.2666667* snoise(2.0*m)
              +0.1333333* snoise(4.0*m)
              +0.0666667* snoise(8.0*m);
      }\n` + shader.fragmentShader;
			shader.fragmentShader = shader.fragmentShader.replace("#include ", `
        #ifdef USE_TRANSMISSION
          // Transmission code is based on glTF-Sampler-Viewer
          // https://github.com/KhronosGroup/glTF-Sample-Viewer
          uniform float _transmission;
          uniform float thickness;
          uniform float attenuationDistance;
          uniform vec3 attenuationColor;
          #ifdef USE_TRANSMISSIONMAP
            uniform sampler2D transmissionMap;
          #endif
          #ifdef USE_THICKNESSMAP
            uniform sampler2D thicknessMap;
          #endif
          uniform vec2 transmissionSamplerSize;
          uniform sampler2D transmissionSamplerMap;
          uniform mat4 modelMatrix;
          uniform mat4 projectionMatrix;
          varying vec3 vWorldPosition;
          vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {
            // Direction of refracted light.
            vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );
            // Compute rotation-independant scaling of the model matrix.
            vec3 modelScale;
            modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );
            modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );
            modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );
            // The thickness is specified in local space.
            return normalize( refractionVector ) * thickness * modelScale;
          }
          float applyIorToRoughness( const in float roughness, const in float ior ) {
            // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and
            // an IOR of 1.5 results in the default amount of microfacet refraction.
            return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );
          }
          vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {
            float framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );            
            #ifdef USE_SAMPLER
              #ifdef texture2DLodEXT
                return texture2DLodEXT(transmissionSamplerMap, fragCoord.xy, framebufferLod);
              #else
                return texture2D(transmissionSamplerMap, fragCoord.xy, framebufferLod);
              #endif
            #else
              return texture2D(buffer, fragCoord.xy);
            #endif
          }
          vec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {
            if ( isinf( attenuationDistance ) ) {
              // Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all.
              return radiance;
            } else {
              // Compute light attenuation using Beer's law.
              vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;
              vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); // Beer's law
              return transmittance * radiance;
            }
          }
          vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,
            const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,
            const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,
            const in vec3 attenuationColor, const in float attenuationDistance ) {
            vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );
            vec3 refractedRayExit = position + transmissionRay;
            // Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
            vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );
            vec2 refractionCoords = ndcPos.xy / ndcPos.w;
            refractionCoords += 1.0;
            refractionCoords /= 2.0;
            // Sample framebuffer to get pixel the refracted ray hits.
            vec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );
            vec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );
            // Get the specular component.
            vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );
            return vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );
          }
        #endif\n`);
			shader.fragmentShader = shader.fragmentShader.replace("#include ", `  
        // Improve the refraction to use the world pos
        material.transmission = _transmission;
        material.transmissionAlpha = 1.0;
        material.thickness = thickness;
        material.attenuationDistance = attenuationDistance;
        material.attenuationColor = attenuationColor;
        #ifdef USE_TRANSMISSIONMAP
          material.transmission *= texture2D( transmissionMap, vUv ).r;
        #endif
        #ifdef USE_THICKNESSMAP
          material.thickness *= texture2D( thicknessMap, vUv ).g;
        #endif
        
        vec3 pos = vWorldPosition;
        float runningSeed = 0.0;
        vec3 v = normalize( cameraPosition - pos );
        vec3 n = inverseTransformDirection( normal, viewMatrix );
        vec3 transmission = vec3(0.0);
        float transmissionR, transmissionB, transmissionG;
        float randomCoords = rand(runningSeed++);
        float thickness_smear = thickness * max(pow(roughnessFactor, 0.33), anisotropicBlur);
        vec3 distortionNormal = vec3(0.0);
        vec3 temporalOffset = vec3(time, -time, -time) * temporalDistortion;
        if (distortion > 0.0) {
          distortionNormal = distortion * vec3(snoiseFractal(vec3((pos * distortionScale + temporalOffset))), snoiseFractal(vec3(pos.zxy * distortionScale - temporalOffset)), snoiseFractal(vec3(pos.yxz * distortionScale + temporalOffset)));
        }
        for (float i = 0.0; i < ${samples}.0; i ++) {
          vec3 sampleNorm = normalize(n + roughnessFactor * roughnessFactor * 2.0 * normalize(vec3(rand(runningSeed++) - 0.5, rand(runningSeed++) - 0.5, rand(runningSeed++) - 0.5)) * pow(rand(runningSeed++), 0.33) + distortionNormal);
          transmissionR = getIBLVolumeRefraction(
            sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,
            pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness  + thickness_smear * (i + randomCoords) / float(${samples}),
            material.attenuationColor, material.attenuationDistance
          ).r;
          transmissionG = getIBLVolumeRefraction(
            sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,
            pos, modelMatrix, viewMatrix, projectionMatrix, material.ior  * (1.0 + chromaticAberration * (i + randomCoords) / float(${samples})) , material.thickness + thickness_smear * (i + randomCoords) / float(${samples}),
            material.attenuationColor, material.attenuationDistance
          ).g;
          transmissionB = getIBLVolumeRefraction(
            sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,
            pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + 2.0 * chromaticAberration * (i + randomCoords) / float(${samples})), material.thickness + thickness_smear * (i + randomCoords) / float(${samples}),
            material.attenuationColor, material.attenuationDistance
          ).b;
          transmission.r += transmissionR;
          transmission.g += transmissionG;
          transmission.b += transmissionB;
        }
        transmission /= ${samples}.0;
        totalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n`);
		};
		Object.keys(this.uniforms).forEach((name) => Object.defineProperty(this, name, {
			get: () => this.uniforms[name].value,
			set: (v) => this.uniforms[name].value = v
		}));
	}
};
var MeshTransmissionMaterial = /* @__PURE__ */ import_react.forwardRef(({ buffer, transmissionSampler = false, backside = false, side = 0, transmission = 1, thickness = 0, backsideThickness = 0, backsideEnvMapIntensity = 1, samples = 10, resolution, backsideResolution, background, anisotropy, anisotropicBlur, ...props }, fref) => {
	extend({ MeshTransmissionMaterial: MeshTransmissionMaterialImpl });
	const ref = import_react.useRef(null);
	const [discardMaterial] = import_react.useState(() => new DiscardMaterial());
	const fboBack = useFBO(backsideResolution || resolution);
	const fboMain = useFBO(resolution);
	let oldBg;
	let oldEnvMapIntensity;
	let oldTone;
	let parent;
	useFrame((state) => {
		ref.current.time = state.clock.elapsedTime;
		if (ref.current.buffer === fboMain.texture && !transmissionSampler) {
			var _r3f$parent;
			parent = (_r3f$parent = ref.current.__r3f.parent) == null ? void 0 : _r3f$parent.object;
			if (parent) {
				oldTone = state.gl.toneMapping;
				oldBg = state.scene.background;
				oldEnvMapIntensity = ref.current.envMapIntensity;
				state.gl.toneMapping = 0;
				if (background) state.scene.background = background;
				parent.material = discardMaterial;
				if (backside) {
					state.gl.setRenderTarget(fboBack);
					state.gl.render(state.scene, state.camera);
					parent.material = ref.current;
					parent.material.buffer = fboBack.texture;
					parent.material.thickness = backsideThickness;
					parent.material.side = 1;
					parent.material.envMapIntensity = backsideEnvMapIntensity;
				}
				state.gl.setRenderTarget(fboMain);
				state.gl.render(state.scene, state.camera);
				parent.material = ref.current;
				parent.material.thickness = thickness;
				parent.material.side = side;
				parent.material.buffer = fboMain.texture;
				parent.material.envMapIntensity = oldEnvMapIntensity;
				state.scene.background = oldBg;
				state.gl.setRenderTarget(null);
				state.gl.toneMapping = oldTone;
			}
		}
	});
	import_react.useImperativeHandle(fref, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("meshTransmissionMaterial", _extends$1({
		args: [samples, transmissionSampler],
		ref
	}, props, {
		buffer: buffer || fboMain.texture,
		_transmission: transmission,
		anisotropicBlur: anisotropicBlur !== null && anisotropicBlur !== void 0 ? anisotropicBlur : anisotropy,
		transmission: transmissionSampler ? transmission : 0,
		thickness,
		side
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/MeshDiscardMaterial.js
var MeshDiscardMaterial = /* @__PURE__ */ import_react.forwardRef((props, fref) => {
	extend({ DiscardMaterialImpl: DiscardMaterial });
	return /*#__PURE__*/ import_react.createElement("discardMaterialImpl", _extends$1({ ref: fref }, props));
});
//#endregion
//#region node_modules/@react-three/drei/core/MultiMaterial.js
function MultiMaterial(props) {
	const group = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		const parent = group.current.parent;
		const geometry = parent == null ? void 0 : parent.geometry;
		if (geometry) {
			const oldMaterial = parent.material;
			parent.material = group.current.__r3f.children.map((instance) => instance.object);
			const oldGroups = [...geometry.groups];
			geometry.clearGroups();
			parent.material.forEach((material, index) => {
				if (index < parent.material.length - 1) material.depthWrite = false;
				geometry.addGroup(0, Infinity, index);
			});
			return () => {
				parent.material = oldMaterial;
				geometry.groups = oldGroups;
			};
		}
	});
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: group }, props));
}
//#endregion
//#region node_modules/@react-three/drei/core/PointMaterial.js
var opaque_fragment = version$1 >= 154 ? "opaque_fragment" : "output_fragment";
var PointMaterialImpl = class extends PointsMaterial {
	constructor(props) {
		super(props);
		this.onBeforeCompile = (shader, renderer) => {
			const { isWebGL2 } = renderer.capabilities;
			shader.fragmentShader = shader.fragmentShader.replace(`#include <${opaque_fragment}>`, `
        ${!isWebGL2 ? `#extension GL_OES_standard_derivatives : enable\n#include <${opaque_fragment}>` : `#include <${opaque_fragment}>`}
      vec2 cxy = 2.0 * gl_PointCoord - 1.0;
      float r = dot(cxy, cxy);
      float delta = fwidth(r);     
      float mask = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
      gl_FragColor = vec4(gl_FragColor.rgb, mask * gl_FragColor.a );
      #include 
      #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
      `);
		};
	}
};
var PointMaterial = /* @__PURE__ */ import_react.forwardRef((props, ref) => {
	const [material] = import_react.useState(() => new PointMaterialImpl(null));
	return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({}, props, {
		object: material,
		ref,
		attach: "material"
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/softShadows.js
var pcss = ({ focus = 0, size = 25, samples = 10 } = {}) => `
#define PENUMBRA_FILTER_SIZE float(${size})
#define RGB_NOISE_FUNCTION(uv) (randRGB(uv))
vec3 randRGB(vec2 uv) {
  return vec3(
    fract(sin(dot(uv, vec2(12.75613, 38.12123))) * 13234.76575),
    fract(sin(dot(uv, vec2(19.45531, 58.46547))) * 43678.23431),
    fract(sin(dot(uv, vec2(23.67817, 78.23121))) * 93567.23423)
  );
}

vec3 lowPassRandRGB(vec2 uv) {
  // 3x3 convolution (average)
  // can be implemented as separable with an extra buffer for a total of 6 samples instead of 9
  vec3 result = vec3(0);
  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));
  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0,  0.0));
  result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, +1.0));
  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, -1.0));
  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0,  0.0));
  result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, +1.0));
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0,  0.0));
  result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));
  result *= 0.111111111; // 1.0 / 9.0
  return result;
}
vec3 highPassRandRGB(vec2 uv) {
  // by subtracting the low-pass signal from the original signal, we're being left with the high-pass signal
  // hp(x) = x - lp(x)
  return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;
}


vec2 vogelDiskSample(int sampleIndex, int sampleCount, float angle) {
  const float goldenAngle = 2.399963f; // radians
  float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));
  float theta = float(sampleIndex) * goldenAngle + angle;
  float sine = sin(theta);
  float cosine = cos(theta);
  return vec2(cosine, sine) * r;
}
float penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation
  return (zReceiver - zBlocker) / zBlocker;
}
float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
  float blockerDepthSum = float(${focus});
  float blockers = 0.0;

  int j = 0;
  vec2 offset = vec2(0.);
  float depth = 0.;

  #pragma unroll_loop_start
  for(int i = 0; i < ${samples}; i ++) {
    offset = (vogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;
    depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset));
    if (depth < compare) {
      blockerDepthSum += depth;
      blockers++;
    }
    j++;
  }
  #pragma unroll_loop_end

  if (blockers > 0.0) {
    return blockerDepthSum / blockers;
  }
  return -1.0;
}

        
float vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {
  float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
  float shadow = 0.0f;
  int j = 0;
  vec2 vogelSample = vec2(0.0);
  vec2 offset = vec2(0.0);
  #pragma unroll_loop_start
  for (int i = 0; i < ${samples}; i++) {
    vogelSample = vogelDiskSample(j, ${samples}, angle) * texelSize;
    offset = vogelSample * (1.0 + filterRadius * float(${size}));
    shadow += step( zReceiver, unpackRGBAToDepth( texture2D( shadowMap, uv + offset ) ) );
    j++;
  }
  #pragma unroll_loop_end
  return shadow * 1.0 / ${samples}.0;
}

float PCSS (sampler2D shadowMap, vec4 coords) {
  vec2 uv = coords.xy;
  float zReceiver = coords.z; // Assumed to be eye-space z in this code
  float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;
  float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);
  if (avgBlockerDepth == -1.0) {
    return 1.0;
  }
  float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);
  return vogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);
}`;
function reset(gl, scene, camera) {
	scene.traverse((object) => {
		if (object.material) {
			gl.properties.remove(object.material);
			object.material.dispose == null || object.material.dispose();
		}
	});
	gl.info.programs.length = 0;
	gl.compile(scene, camera);
}
function SoftShadows({ focus = 0, samples = 10, size = 25 }) {
	const gl = useThree((state) => state.gl);
	const scene = useThree((state) => state.scene);
	const camera = useThree((state) => state.camera);
	import_react.useEffect(() => {
		const original = ShaderChunk.shadowmap_pars_fragment;
		ShaderChunk.shadowmap_pars_fragment = ShaderChunk.shadowmap_pars_fragment.replace("#ifdef USE_SHADOWMAP", "#ifdef USE_SHADOWMAP\n" + pcss({
			size,
			samples,
			focus
		})).replace("#if defined( SHADOWMAP_TYPE_PCF )", "\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )");
		reset(gl, scene, camera);
		return () => {
			ShaderChunk.shadowmap_pars_fragment = original;
			reset(gl, scene, camera);
		};
	}, [
		focus,
		size,
		samples
	]);
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/shapes.js
function create$1(type, effect) {
	const El = type + "Geometry";
	return /*#__PURE__*/ import_react.forwardRef(({ args, children, ...props }, fref) => {
		const ref = import_react.useRef(null);
		import_react.useImperativeHandle(fref, () => ref.current);
		import_react.useLayoutEffect(() => void (effect == null ? void 0 : effect(ref.current)));
		return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement(El, {
			attach: "geometry",
			args
		}), children);
	});
}
var Box = /* @__PURE__ */ create$1("box");
var Circle = /* @__PURE__ */ create$1("circle");
var Cone = /* @__PURE__ */ create$1("cone");
var Cylinder = /* @__PURE__ */ create$1("cylinder");
var Sphere = /* @__PURE__ */ create$1("sphere");
var Plane = /* @__PURE__ */ create$1("plane");
var Tube = /* @__PURE__ */ create$1("tube");
var Torus = /* @__PURE__ */ create$1("torus");
var TorusKnot = /* @__PURE__ */ create$1("torusKnot");
var Tetrahedron = /* @__PURE__ */ create$1("tetrahedron");
var Ring = /* @__PURE__ */ create$1("ring");
var Polyhedron = /* @__PURE__ */ create$1("polyhedron");
var Icosahedron = /* @__PURE__ */ create$1("icosahedron");
var Octahedron = /* @__PURE__ */ create$1("octahedron");
var Dodecahedron = /* @__PURE__ */ create$1("dodecahedron");
var Extrude = /* @__PURE__ */ create$1("extrude");
var Lathe = /* @__PURE__ */ create$1("lathe");
var Capsule = /* @__PURE__ */ create$1("capsule");
var Shape = /* @__PURE__ */ create$1("shape", ({ geometry }) => {
	const pos = geometry.attributes.position;
	const b3 = new Box3().setFromBufferAttribute(pos);
	const b3size = new Vector3();
	b3.getSize(b3size);
	const uv = [];
	let x = 0, y = 0, u = 0, v = 0;
	for (let i = 0; i < pos.count; i++) {
		x = pos.getX(i);
		y = pos.getY(i);
		u = (x - b3.min.x) / b3size.x;
		v = (y - b3.min.y) / b3size.y;
		uv.push(u, v);
	}
	geometry.setAttribute("uv", new Float32BufferAttribute(uv, 2));
});
//#endregion
//#region node_modules/@react-three/drei/core/RoundedBox.js
var eps = 1e-5;
function createShape(width, height, radius0) {
	const shape = new Shape$1();
	const radius = radius0 - eps;
	shape.absarc(eps, eps, eps, -Math.PI / 2, -Math.PI, true);
	shape.absarc(eps, height - radius * 2, eps, Math.PI, Math.PI / 2, true);
	shape.absarc(width - radius * 2, height - radius * 2, eps, Math.PI / 2, 0, true);
	shape.absarc(width - radius * 2, eps, eps, 0, -Math.PI / 2, true);
	return shape;
}
var RoundedBox = /* @__PURE__ */ import_react.forwardRef(function RoundedBox({ args: [width = 1, height = 1, depth = 1] = [], radius = .05, steps = 1, smoothness = 4, bevelSegments = 4, creaseAngle = .4, children, ...rest }, ref) {
	return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref }, rest), /*#__PURE__*/ import_react.createElement(RoundedBoxGeometry, {
		args: [
			width,
			height,
			depth
		],
		radius,
		steps,
		smoothness,
		bevelSegments,
		creaseAngle
	}), children);
});
var RoundedBoxGeometry = /* @__PURE__ */ import_react.forwardRef(function RoundedBoxGeometry({ args: [width = 1, height = 1, depth = 1] = [], radius = .05, steps = 1, smoothness = 4, bevelSegments = 4, creaseAngle = .4, ...rest }, ref) {
	const shape = import_react.useMemo(() => createShape(width, height, radius), [
		width,
		height,
		radius
	]);
	const params = import_react.useMemo(() => ({
		depth: depth - radius * 2,
		bevelEnabled: true,
		bevelSegments: bevelSegments * 2,
		steps,
		bevelSize: radius - eps,
		bevelThickness: radius,
		curveSegments: smoothness
	}), [
		depth,
		radius,
		smoothness,
		bevelSegments,
		steps
	]);
	const geomRef = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		if (geomRef.current) {
			geomRef.current.center();
			toCreasedNormals(geomRef.current, creaseAngle);
		}
	}, [
		shape,
		params,
		creaseAngle
	]);
	import_react.useImperativeHandle(ref, () => geomRef.current);
	return /*#__PURE__*/ import_react.createElement("extrudeGeometry", _extends$1({
		ref: geomRef,
		args: [shape, params]
	}, rest));
});
//#endregion
//#region node_modules/@react-three/drei/core/ScreenQuad.js
function createScreenQuadGeometry() {
	const geometry = new BufferGeometry();
	const vertices = new Float32Array([
		-1,
		-1,
		3,
		-1,
		-1,
		3
	]);
	geometry.boundingSphere = new Sphere$1();
	geometry.boundingSphere.set(new Vector3(), Infinity);
	geometry.setAttribute("position", new BufferAttribute(vertices, 2));
	return geometry;
}
var ScreenQuad = /* @__PURE__ */ import_react.forwardRef(function ScreenQuad({ children, ...restProps }, ref) {
	const geometry = import_react.useMemo(createScreenQuadGeometry, []);
	return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({
		ref,
		geometry,
		frustumCulled: false
	}, restProps), children);
});
//#endregion
//#region node_modules/@react-three/drei/core/Resize.js
var Resize = /* @__PURE__ */ import_react.forwardRef(({ children, width, height, depth, box3, precise = true, ...props }, fRef) => {
	const ref = import_react.useRef(null);
	const outer = import_react.useRef(null);
	const inner = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		outer.current.matrixWorld.identity();
		let box = box3 || new Box3().setFromObject(inner.current, precise);
		const w = box.max.x - box.min.x;
		const h = box.max.y - box.min.y;
		const d = box.max.z - box.min.z;
		let dimension = Math.max(w, h, d);
		if (width) dimension = w;
		if (height) dimension = h;
		if (depth) dimension = d;
		outer.current.scale.setScalar(1 / dimension);
	}, [
		width,
		height,
		depth,
		box3,
		precise
	]);
	import_react.useImperativeHandle(fRef, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement("group", { ref: outer }, /*#__PURE__*/ import_react.createElement("group", { ref: inner }, children)));
});
//#endregion
//#region node_modules/@react-three/drei/core/Bounds.js
var AnimationState = /*#__PURE__*/ function(AnimationState) {
	AnimationState[AnimationState["NONE"] = 0] = "NONE";
	AnimationState[AnimationState["START"] = 1] = "START";
	AnimationState[AnimationState["ACTIVE"] = 2] = "ACTIVE";
	return AnimationState;
}(AnimationState || {});
var isOrthographic = (def) => def && def.isOrthographicCamera;
var isBox3 = (def) => def && def.isBox3;
var interpolateFuncDefault = (t) => {
	return 1 - Math.exp(-5 * t) + .007 * t;
};
var context$5 = /*#__PURE__*/ import_react.createContext(null);
function Bounds({ children, maxDuration = 1, margin = 1.2, observe, fit, clip, interpolateFunc = interpolateFuncDefault, onFit }) {
	const ref = import_react.useRef(null);
	const { camera, size, invalidate } = useThree();
	const controls = useThree((state) => state.controls);
	const onFitRef = import_react.useRef(onFit);
	onFitRef.current = onFit;
	const origin = import_react.useRef({
		camPos: new Vector3(),
		camRot: new Quaternion(),
		camZoom: 1
	});
	const goal = import_react.useRef({
		camPos: void 0,
		camRot: void 0,
		camZoom: void 0,
		camUp: void 0,
		target: void 0
	});
	const animationState = import_react.useRef(AnimationState.NONE);
	const t = import_react.useRef(0);
	const [box] = import_react.useState(() => new Box3());
	const api = import_react.useMemo(() => {
		function getSize() {
			const boxSize = box.getSize(new Vector3());
			const center = box.getCenter(new Vector3());
			const maxSize = Math.max(boxSize.x, boxSize.y, boxSize.z);
			const fitHeightDistance = isOrthographic(camera) ? maxSize * 4 : maxSize / (2 * Math.atan(Math.PI * camera.fov / 360));
			const fitWidthDistance = isOrthographic(camera) ? maxSize * 4 : fitHeightDistance / camera.aspect;
			return {
				box,
				size: boxSize,
				center,
				distance: margin * Math.max(fitHeightDistance, fitWidthDistance)
			};
		}
		return {
			getSize,
			refresh(object) {
				if (isBox3(object)) box.copy(object);
				else {
					const target = object || ref.current;
					if (!target) return this;
					target.updateWorldMatrix(true, true);
					box.setFromObject(target);
				}
				if (box.isEmpty()) {
					const max = camera.position.length() || 10;
					box.setFromCenterAndSize(new Vector3(), new Vector3(max, max, max));
				}
				origin.current.camPos.copy(camera.position);
				origin.current.camRot.copy(camera.quaternion);
				isOrthographic(camera) && (origin.current.camZoom = camera.zoom);
				goal.current.camPos = void 0;
				goal.current.camRot = void 0;
				goal.current.camZoom = void 0;
				goal.current.camUp = void 0;
				goal.current.target = void 0;
				return this;
			},
			reset() {
				const { center, distance } = getSize();
				const direction = camera.position.clone().sub(center).normalize();
				goal.current.camPos = center.clone().addScaledVector(direction, distance);
				goal.current.target = center.clone();
				const mCamRot = new Matrix4().lookAt(goal.current.camPos, goal.current.target, camera.up);
				goal.current.camRot = new Quaternion().setFromRotationMatrix(mCamRot);
				animationState.current = AnimationState.START;
				t.current = 0;
				return this;
			},
			moveTo(position) {
				goal.current.camPos = Array.isArray(position) ? new Vector3(...position) : position.clone();
				animationState.current = AnimationState.START;
				t.current = 0;
				return this;
			},
			lookAt({ target, up }) {
				goal.current.target = Array.isArray(target) ? new Vector3(...target) : target.clone();
				if (up) goal.current.camUp = Array.isArray(up) ? new Vector3(...up) : up.clone();
				else goal.current.camUp = camera.up.clone();
				const mCamRot = new Matrix4().lookAt(goal.current.camPos || camera.position, goal.current.target, goal.current.camUp);
				goal.current.camRot = new Quaternion().setFromRotationMatrix(mCamRot);
				animationState.current = AnimationState.START;
				t.current = 0;
				return this;
			},
			/**
			* @deprecated Use moveTo and lookAt instead
			*/
			to({ position, target }) {
				return this.moveTo(position).lookAt({ target });
			},
			fit() {
				if (!isOrthographic(camera)) return this.reset();
				let maxHeight = 0, maxWidth = 0;
				const vertices = [
					new Vector3(box.min.x, box.min.y, box.min.z),
					new Vector3(box.min.x, box.max.y, box.min.z),
					new Vector3(box.min.x, box.min.y, box.max.z),
					new Vector3(box.min.x, box.max.y, box.max.z),
					new Vector3(box.max.x, box.max.y, box.max.z),
					new Vector3(box.max.x, box.max.y, box.min.z),
					new Vector3(box.max.x, box.min.y, box.max.z),
					new Vector3(box.max.x, box.min.y, box.min.z)
				];
				const pos = goal.current.camPos || camera.position;
				const target = goal.current.target || (controls == null ? void 0 : controls.target);
				const up = goal.current.camUp || camera.up;
				const mCamWInv = target ? new Matrix4().lookAt(pos, target, up).setPosition(pos).invert() : camera.matrixWorldInverse;
				for (const v of vertices) {
					v.applyMatrix4(mCamWInv);
					maxHeight = Math.max(maxHeight, Math.abs(v.y));
					maxWidth = Math.max(maxWidth, Math.abs(v.x));
				}
				maxHeight *= 2;
				maxWidth *= 2;
				const zoomForHeight = (camera.top - camera.bottom) / maxHeight;
				const zoomForWidth = (camera.right - camera.left) / maxWidth;
				goal.current.camZoom = Math.min(zoomForHeight, zoomForWidth) / margin;
				animationState.current = AnimationState.START;
				t.current = 0;
				onFitRef.current && onFitRef.current(this.getSize());
				return this;
			},
			clip() {
				const { distance } = getSize();
				camera.near = distance / 100;
				camera.far = distance * 100;
				camera.updateProjectionMatrix();
				if (controls) {
					controls.maxDistance = distance * 10;
					controls.update();
				}
				invalidate();
				return this;
			}
		};
	}, [
		box,
		camera,
		controls,
		margin,
		invalidate
	]);
	import_react.useLayoutEffect(() => {
		if (controls) {
			const callback = () => {
				if (controls && goal.current.target && animationState.current !== AnimationState.NONE) {
					const front = new Vector3().setFromMatrixColumn(camera.matrix, 2);
					const d0 = origin.current.camPos.distanceTo(controls.target);
					const d1 = (goal.current.camPos || origin.current.camPos).distanceTo(goal.current.target);
					const d = (1 - t.current) * d0 + t.current * d1;
					controls.target.copy(camera.position).addScaledVector(front, -d);
					controls.update();
				}
				animationState.current = AnimationState.NONE;
			};
			controls.addEventListener("start", callback);
			return () => controls.removeEventListener("start", callback);
		}
	}, [controls]);
	const count = import_react.useRef(0);
	import_react.useLayoutEffect(() => {
		if (observe || count.current++ === 0) {
			api.refresh();
			if (fit) api.reset().fit();
			if (clip) api.clip();
		}
	}, [
		size,
		clip,
		fit,
		observe,
		camera,
		controls
	]);
	useFrame((state, delta) => {
		if (animationState.current === AnimationState.START) {
			animationState.current = AnimationState.ACTIVE;
			invalidate();
		} else if (animationState.current === AnimationState.ACTIVE) {
			t.current += delta / maxDuration;
			if (t.current >= 1) {
				goal.current.camPos && camera.position.copy(goal.current.camPos);
				goal.current.camRot && camera.quaternion.copy(goal.current.camRot);
				goal.current.camUp && camera.up.copy(goal.current.camUp);
				goal.current.camZoom && isOrthographic(camera) && (camera.zoom = goal.current.camZoom);
				camera.updateMatrixWorld();
				camera.updateProjectionMatrix();
				if (controls && goal.current.target) {
					controls.target.copy(goal.current.target);
					controls.update();
				}
				animationState.current = AnimationState.NONE;
			} else {
				const k = interpolateFunc(t.current);
				goal.current.camPos && camera.position.lerpVectors(origin.current.camPos, goal.current.camPos, k);
				goal.current.camRot && camera.quaternion.slerpQuaternions(origin.current.camRot, goal.current.camRot, k);
				goal.current.camUp && camera.up.set(0, 1, 0).applyQuaternion(camera.quaternion);
				goal.current.camZoom && isOrthographic(camera) && (camera.zoom = (1 - k) * origin.current.camZoom + k * goal.current.camZoom);
				camera.updateMatrixWorld();
				camera.updateProjectionMatrix();
			}
			invalidate();
		}
	});
	return /*#__PURE__*/ import_react.createElement("group", { ref }, /*#__PURE__*/ import_react.createElement(context$5.Provider, { value: api }, children));
}
function useBounds() {
	return import_react.useContext(context$5);
}
//#endregion
//#region node_modules/@react-three/drei/core/CameraShake.js
var CameraShake = /* @__PURE__ */ import_react.forwardRef(({ intensity = 1, decay, decayRate = .65, maxYaw = .1, maxPitch = .1, maxRoll = .1, yawFrequency = .1, pitchFrequency = .1, rollFrequency = .1 }, ref) => {
	const camera = useThree((state) => state.camera);
	const defaultControls = useThree((state) => state.controls);
	const intensityRef = import_react.useRef(intensity);
	const initialRotation = import_react.useRef(camera.rotation.clone());
	const [yawNoise] = import_react.useState(() => new SimplexNoise());
	const [pitchNoise] = import_react.useState(() => new SimplexNoise());
	const [rollNoise] = import_react.useState(() => new SimplexNoise());
	const constrainIntensity = () => {
		if (intensityRef.current < 0 || intensityRef.current > 1) intensityRef.current = intensityRef.current < 0 ? 0 : 1;
	};
	import_react.useImperativeHandle(ref, () => ({
		getIntensity: () => intensityRef.current,
		setIntensity: (val) => {
			intensityRef.current = val;
			constrainIntensity();
		}
	}), []);
	import_react.useEffect(() => {
		if (defaultControls) {
			const callback = () => void (initialRotation.current = camera.rotation.clone());
			defaultControls.addEventListener("change", callback);
			callback();
			return () => void defaultControls.removeEventListener("change", callback);
		}
	}, [camera, defaultControls]);
	useFrame((state, delta) => {
		const shake = Math.pow(intensityRef.current, 2);
		const yaw = maxYaw * shake * yawNoise.noise(state.clock.elapsedTime * yawFrequency, 1);
		const pitch = maxPitch * shake * pitchNoise.noise(state.clock.elapsedTime * pitchFrequency, 1);
		const roll = maxRoll * shake * rollNoise.noise(state.clock.elapsedTime * rollFrequency, 1);
		camera.rotation.set(initialRotation.current.x + pitch, initialRotation.current.y + yaw, initialRotation.current.z + roll);
		if (decay && intensityRef.current > 0) {
			intensityRef.current -= decayRate * delta;
			constrainIntensity();
		}
	});
	return null;
});
//#endregion
//#region node_modules/@react-three/drei/core/Float.js
var Float = /* @__PURE__ */ import_react.forwardRef(({ children, enabled = true, speed = 1, rotationIntensity = 1, floatIntensity = 1, floatingRange = [-.1, .1], autoInvalidate = false, ...props }, forwardRef) => {
	const ref = import_react.useRef(null);
	import_react.useImperativeHandle(forwardRef, () => ref.current, []);
	const offset = import_react.useRef(Math.random() * 1e4);
	useFrame((state) => {
		var _floatingRange$, _floatingRange$2;
		if (!enabled || speed === 0) return;
		if (autoInvalidate) state.invalidate();
		const t = offset.current + state.clock.elapsedTime;
		ref.current.rotation.x = Math.cos(t / 4 * speed) / 8 * rotationIntensity;
		ref.current.rotation.y = Math.sin(t / 4 * speed) / 8 * rotationIntensity;
		ref.current.rotation.z = Math.sin(t / 4 * speed) / 20 * rotationIntensity;
		let yPosition = Math.sin(t / 4 * speed) / 10;
		yPosition = MathUtils.mapLinear(yPosition, -.1, .1, (_floatingRange$ = floatingRange == null ? void 0 : floatingRange[0]) !== null && _floatingRange$ !== void 0 ? _floatingRange$ : -.1, (_floatingRange$2 = floatingRange == null ? void 0 : floatingRange[1]) !== null && _floatingRange$2 !== void 0 ? _floatingRange$2 : .1);
		ref.current.position.y = yPosition * floatIntensity;
		ref.current.updateMatrix();
	});
	return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement("group", {
		ref,
		matrixAutoUpdate: false
	}, children));
});
//#endregion
//#region node_modules/@monogrid/gainmap-js/dist/QuadRenderer-Bj1xl_EK.js
/**
* @monogrid/gainmap-js v3.4.0
* With ❤️, by MONOGRID 
*/
var getBufferForType = (type, width, height) => {
	let out;
	switch (type) {
		case UnsignedByteType:
			out = new Uint8ClampedArray(width * height * 4);
			break;
		case HalfFloatType:
			out = new Uint16Array(width * height * 4);
			break;
		case UnsignedIntType:
			out = new Uint32Array(width * height * 4);
			break;
		case ByteType:
			out = new Int8Array(width * height * 4);
			break;
		case ShortType:
			out = new Int16Array(width * height * 4);
			break;
		case IntType:
			out = new Int32Array(width * height * 4);
			break;
		case FloatType:
			out = new Float32Array(width * height * 4);
			break;
		default: throw new Error("Unsupported data type");
	}
	return out;
};
var _canReadPixelsResult;
/**
* Test if this browser implementation can correctly read pixels from the specified
* Render target type.
*
* Runs only once
*
* @param type
* @param renderer
* @param camera
* @param renderTargetOptions
* @returns
*/
var canReadPixels = (type, renderer, camera, renderTargetOptions) => {
	if (_canReadPixelsResult !== void 0) return _canReadPixelsResult;
	const testRT = new WebGLRenderTarget(1, 1, renderTargetOptions);
	renderer.setRenderTarget(testRT);
	const mesh = new Mesh(new PlaneGeometry(), new MeshBasicMaterial({ color: 16777215 }));
	renderer.render(mesh, camera);
	renderer.setRenderTarget(null);
	const out = getBufferForType(type, testRT.width, testRT.height);
	renderer.readRenderTargetPixels(testRT, 0, 0, testRT.width, testRT.height, out);
	testRT.dispose();
	mesh.geometry.dispose();
	mesh.material.dispose();
	_canReadPixelsResult = out[0] !== 0;
	return _canReadPixelsResult;
};
/**
* Utility class used for rendering a texture with a material
*
* @category Core
* @group Core
*/
var QuadRenderer = class QuadRenderer {
	_renderer;
	_rendererIsDisposable = false;
	_material;
	_scene;
	_camera;
	_quad;
	_renderTarget;
	_width;
	_height;
	_type;
	_colorSpace;
	_supportsReadPixels = true;
	/**
	* Constructs a new QuadRenderer
	*
	* @param options Parameters for this QuadRenderer
	*/
	constructor(options) {
		this._width = options.width;
		this._height = options.height;
		this._type = options.type;
		this._colorSpace = options.colorSpace;
		const rtOptions = {
			format: RGBAFormat,
			depthBuffer: false,
			stencilBuffer: false,
			type: this._type,
			colorSpace: this._colorSpace,
			anisotropy: options.renderTargetOptions?.anisotropy !== void 0 ? options.renderTargetOptions?.anisotropy : 1,
			generateMipmaps: options.renderTargetOptions?.generateMipmaps !== void 0 ? options.renderTargetOptions?.generateMipmaps : false,
			magFilter: options.renderTargetOptions?.magFilter !== void 0 ? options.renderTargetOptions?.magFilter : LinearFilter,
			minFilter: options.renderTargetOptions?.minFilter !== void 0 ? options.renderTargetOptions?.minFilter : LinearFilter,
			samples: options.renderTargetOptions?.samples !== void 0 ? options.renderTargetOptions?.samples : void 0,
			wrapS: options.renderTargetOptions?.wrapS !== void 0 ? options.renderTargetOptions?.wrapS : ClampToEdgeWrapping,
			wrapT: options.renderTargetOptions?.wrapT !== void 0 ? options.renderTargetOptions?.wrapT : ClampToEdgeWrapping
		};
		this._material = options.material;
		if (options.renderer) this._renderer = options.renderer;
		else {
			this._renderer = QuadRenderer.instantiateRenderer();
			this._rendererIsDisposable = true;
		}
		this._scene = new Scene();
		this._camera = new OrthographicCamera$1();
		this._camera.position.set(0, 0, 10);
		this._camera.left = -.5;
		this._camera.right = .5;
		this._camera.top = .5;
		this._camera.bottom = -.5;
		this._camera.updateProjectionMatrix();
		if (!canReadPixels(this._type, this._renderer, this._camera, rtOptions)) {
			let alternativeType;
			switch (this._type) {
				case HalfFloatType:
					alternativeType = this._renderer.extensions.has("EXT_color_buffer_float") ? FloatType : void 0;
					break;
			}
			if (alternativeType !== void 0) {
				console.warn(`This browser does not support reading pixels from ${this._type} RenderTargets, switching to ${FloatType}`);
				this._type = alternativeType;
			} else {
				this._supportsReadPixels = false;
				console.warn("This browser dos not support toArray or toDataTexture, calls to those methods will result in an error thrown");
			}
		}
		this._quad = new Mesh(new PlaneGeometry(), this._material);
		this._quad.geometry.computeBoundingBox();
		this._scene.add(this._quad);
		this._renderTarget = new WebGLRenderTarget(this.width, this.height, rtOptions);
		this._renderTarget.texture.mapping = options.renderTargetOptions?.mapping !== void 0 ? options.renderTargetOptions?.mapping : 300;
	}
	/**
	* Instantiates a temporary renderer
	*
	* @returns
	*/
	static instantiateRenderer() {
		const renderer = new WebGLRenderer();
		renderer.setSize(128, 128);
		return renderer;
	}
	/**
	* Renders the input texture using the specified material
	*/
	render = () => {
		this._renderer.setRenderTarget(this._renderTarget);
		try {
			this._renderer.render(this._scene, this._camera);
		} catch (e) {
			this._renderer.setRenderTarget(null);
			throw e;
		}
		this._renderer.setRenderTarget(null);
	};
	/**
	* Obtains a Buffer containing the rendered texture.
	*
	* @throws Error if the browser cannot read pixels from this RenderTarget type.
	* @returns a TypedArray containing RGBA values from this renderer
	*/
	toArray() {
		if (!this._supportsReadPixels) throw new Error("Can't read pixels in this browser");
		const out = getBufferForType(this._type, this._width, this._height);
		this._renderer.readRenderTargetPixels(this._renderTarget, 0, 0, this._width, this._height, out);
		return out;
	}
	/**
	* Performs a readPixel operation in the renderTarget
	* and returns a DataTexture containing the read data
	*
	* @param options options
	* @returns
	*/
	toDataTexture(options) {
		const returnValue = new DataTexture(this.toArray(), this.width, this.height, RGBAFormat, this._type, options?.mapping || 300, options?.wrapS || 1001, options?.wrapT || 1001, options?.magFilter || 1006, options?.minFilter || 1006, options?.anisotropy || 1, LinearSRGBColorSpace$2);
		returnValue.generateMipmaps = options?.generateMipmaps !== void 0 ? options?.generateMipmaps : false;
		return returnValue;
	}
	/**
	* If using a disposable renderer, it will dispose it.
	*/
	disposeOnDemandRenderer() {
		this._renderer.setRenderTarget(null);
		if (this._rendererIsDisposable) {
			this._renderer.dispose();
			this._renderer.forceContextLoss();
		}
	}
	/**
	* Will dispose of **all** assets used by this renderer.
	*
	*
	* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
	* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
	* or are otherwise done with it.
	*
	* @example
	* ```js
	* const loader = new HDRJPGLoader(renderer)
	* const result = await loader.loadAsync('gainmap.jpeg')
	* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
	* // DO NOT dispose the renderTarget here,
	* // it is used directly in the material
	* result.dispose()
	* ```
	*
	* @example
	* ```js
	* const loader = new HDRJPGLoader(renderer)
	* const pmremGenerator = new PMREMGenerator( renderer );
	* const result = await loader.loadAsync('gainmap.jpeg')
	* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
	* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
	* // renderTarget can be disposed here
	* // because it was used to generate a PMREM texture
	* result.dispose(true)
	* ```
	*/
	dispose(disposeRenderTarget) {
		this.disposeOnDemandRenderer();
		if (disposeRenderTarget) this.renderTarget.dispose();
		if (this.material instanceof ShaderMaterial) Object.values(this.material.uniforms).forEach((v) => {
			if (v.value instanceof Texture$1) v.value.dispose();
		});
		Object.values(this.material).forEach((value) => {
			if (value instanceof Texture$1) value.dispose();
		});
		this.material.dispose();
		this._quad.geometry.dispose();
	}
	/**
	* Width of the texture
	*/
	get width() {
		return this._width;
	}
	set width(value) {
		this._width = value;
		this._renderTarget.setSize(this._width, this._height);
	}
	/**
	* Height of the texture
	*/
	get height() {
		return this._height;
	}
	set height(value) {
		this._height = value;
		this._renderTarget.setSize(this._width, this._height);
	}
	/**
	* The renderer used
	*/
	get renderer() {
		return this._renderer;
	}
	/**
	* The `WebGLRenderTarget` used.
	*/
	get renderTarget() {
		return this._renderTarget;
	}
	set renderTarget(value) {
		this._renderTarget = value;
		this._width = value.width;
		this._height = value.height;
	}
	/**
	* The `Material` used.
	*/
	get material() {
		return this._material;
	}
	/**
	*
	*/
	get type() {
		return this._type;
	}
	get colorSpace() {
		return this._colorSpace;
	}
};
var GainMapNotFoundError = class extends Error {};
var XMPMetadataNotFoundError = class extends Error {};
var getXMLValue = (xml, tag, defaultValue) => {
	const attributeMatch = new RegExp(`${tag}="([^"]*)"`, "i").exec(xml);
	if (attributeMatch) return attributeMatch[1];
	const tagMatch = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)`, "i").exec(xml);
	if (tagMatch) {
		const liValues = tagMatch[1].match(/([^<]*)<\/rdf:li>/g);
		if (liValues && liValues.length === 3) return liValues.map((v) => v.replace(/<\/?rdf:li>/g, ""));
		return tagMatch[1].trim();
	}
	if (defaultValue !== void 0) return defaultValue;
	throw new Error(`Can't find ${tag} in gainmap metadata`);
};
var extractXMP = (input) => {
	let str;
	if (typeof TextDecoder !== "undefined") str = new TextDecoder().decode(input);
	else str = input.toString();
	let start = str.indexOf("", start);
		const xmpBlock = str.slice(start, end + 10);
		try {
			const gainMapMin = getXMLValue(xmpBlock, "hdrgm:GainMapMin", "0");
			const gainMapMax = getXMLValue(xmpBlock, "hdrgm:GainMapMax");
			const gamma = getXMLValue(xmpBlock, "hdrgm:Gamma", "1");
			const offsetSDR = getXMLValue(xmpBlock, "hdrgm:OffsetSDR", "0.015625");
			const offsetHDR = getXMLValue(xmpBlock, "hdrgm:OffsetHDR", "0.015625");
			const hdrCapacityMinMatch = /hdrgm:HDRCapacityMin="([^"]*)"/.exec(xmpBlock);
			const hdrCapacityMin = hdrCapacityMinMatch ? hdrCapacityMinMatch[1] : "0";
			const hdrCapacityMaxMatch = /hdrgm:HDRCapacityMax="([^"]*)"/.exec(xmpBlock);
			if (!hdrCapacityMaxMatch) throw new Error("Incomplete gainmap metadata");
			const hdrCapacityMax = hdrCapacityMaxMatch[1];
			return {
				gainMapMin: Array.isArray(gainMapMin) ? gainMapMin.map((v) => parseFloat(v)) : [
					parseFloat(gainMapMin),
					parseFloat(gainMapMin),
					parseFloat(gainMapMin)
				],
				gainMapMax: Array.isArray(gainMapMax) ? gainMapMax.map((v) => parseFloat(v)) : [
					parseFloat(gainMapMax),
					parseFloat(gainMapMax),
					parseFloat(gainMapMax)
				],
				gamma: Array.isArray(gamma) ? gamma.map((v) => parseFloat(v)) : [
					parseFloat(gamma),
					parseFloat(gamma),
					parseFloat(gamma)
				],
				offsetSdr: Array.isArray(offsetSDR) ? offsetSDR.map((v) => parseFloat(v)) : [
					parseFloat(offsetSDR),
					parseFloat(offsetSDR),
					parseFloat(offsetSDR)
				],
				offsetHdr: Array.isArray(offsetHDR) ? offsetHDR.map((v) => parseFloat(v)) : [
					parseFloat(offsetHDR),
					parseFloat(offsetHDR),
					parseFloat(offsetHDR)
				],
				hdrCapacityMin: parseFloat(hdrCapacityMin),
				hdrCapacityMax: parseFloat(hdrCapacityMax)
			};
		} catch (e) {}
		start = str.indexOf(" {
			const debug = this.options.debug;
			const dataView = new DataView(imageArrayBuffer.buffer);
			if (dataView.getUint16(0) !== 65496) {
				reject(/* @__PURE__ */ new Error("Not a valid jpeg"));
				return;
			}
			const length = dataView.byteLength;
			let offset = 2;
			let loops = 0;
			let marker;
			while (offset < length) {
				if (++loops > 250) {
					reject(/* @__PURE__ */ new Error(`Found no marker after ${loops} loops 😵`));
					return;
				}
				if (dataView.getUint8(offset) !== 255) {
					reject(/* @__PURE__ */ new Error(`Not a valid marker at offset 0x${offset.toString(16)}, found: 0x${dataView.getUint8(offset).toString(16)}`));
					return;
				}
				marker = dataView.getUint8(offset + 1);
				if (debug) console.log(`Marker: ${marker.toString(16)}`);
				if (marker === 226) {
					if (debug) console.log("Found APP2 marker (0xffe2)");
					const formatPt = offset + 4;
					if (dataView.getUint32(formatPt) === 1297106432) {
						const tiffOffset = formatPt + 4;
						let bigEnd;
						if (dataView.getUint16(tiffOffset) === 18761) bigEnd = false;
						else if (dataView.getUint16(tiffOffset) === 19789) bigEnd = true;
						else {
							reject(/* @__PURE__ */ new Error("No valid endianness marker found in TIFF header"));
							return;
						}
						if (dataView.getUint16(tiffOffset + 2, !bigEnd) !== 42) {
							reject(/* @__PURE__ */ new Error("Not valid TIFF data! (no 0x002A marker)"));
							return;
						}
						const firstIFDOffset = dataView.getUint32(tiffOffset + 4, !bigEnd);
						if (firstIFDOffset < 8) {
							reject(/* @__PURE__ */ new Error("Not valid TIFF data! (First offset less than 8)"));
							return;
						}
						const dirStart = tiffOffset + firstIFDOffset;
						const count = dataView.getUint16(dirStart, !bigEnd);
						const entriesStart = dirStart + 2;
						let numberOfImages = 0;
						for (let i = entriesStart; i < entriesStart + 12 * count; i += 12) if (dataView.getUint16(i, !bigEnd) === 45057) numberOfImages = dataView.getUint32(i + 8, !bigEnd);
						const MPImageListValPt = dirStart + 2 + count * 12 + 4;
						const images = [];
						for (let i = MPImageListValPt; i < MPImageListValPt + numberOfImages * 16; i += 16) {
							const image = {
								MPType: dataView.getUint32(i, !bigEnd),
								size: dataView.getUint32(i + 4, !bigEnd),
								dataOffset: dataView.getUint32(i + 8, !bigEnd),
								dependantImages: dataView.getUint32(i + 12, !bigEnd),
								start: -1,
								end: -1,
								isFII: false
							};
							if (!image.dataOffset) {
								image.start = 0;
								image.isFII = true;
							} else {
								image.start = tiffOffset + image.dataOffset;
								image.isFII = false;
							}
							image.end = image.start + image.size;
							images.push(image);
						}
						if (this.options.extractNonFII && images.length) {
							const bufferBlob = new Blob([dataView]);
							const imgs = [];
							for (const image of images) {
								if (image.isFII && !this.options.extractFII) continue;
								const imageBlob = bufferBlob.slice(image.start, image.end + 1, "image/jpeg");
								imgs.push(imageBlob);
							}
							resolve(imgs);
						}
					}
				}
				offset += 2 + dataView.getUint16(offset + 2);
			}
		});
	}
};
/**
* Extracts XMP Metadata and the gain map recovery image
* from a single JPEG file.
*
* @category Decoding Functions
* @group Decoding Functions
* @param jpegFile an `Uint8Array` containing and encoded JPEG file
* @returns an sdr `Uint8Array` compressed in JPEG, a gainMap `Uint8Array` compressed in JPEG and the XMP parsed XMP metadata
* @throws Error if XMP Metadata is not found
* @throws Error if Gain map image is not found
* @example
* import { FileLoader } from 'three'
* import { extractGainmapFromJPEG } from '@monogrid/gainmap-js'
*
* const jpegFile = await new FileLoader()
*  .setResponseType('arraybuffer')
*  .loadAsync('image.jpg')
*
* const { sdr, gainMap, metadata } = extractGainmapFromJPEG(jpegFile)
*/
var extractGainmapFromJPEG = async (jpegFile) => {
	const metadata = extractXMP(jpegFile);
	if (!metadata) throw new XMPMetadataNotFoundError("Gain map XMP metadata not found");
	const images = await new MPFExtractor({
		extractFII: true,
		extractNonFII: true
	}).extract(jpegFile);
	if (images.length !== 2) throw new GainMapNotFoundError("Gain map recovery image not found");
	return {
		sdr: new Uint8Array(await images[0].arrayBuffer()),
		gainMap: new Uint8Array(await images[1].arrayBuffer()),
		metadata
	};
};
/**
* private function, async get image from blob
*
* @param blob
* @returns
*/
var getHTMLImageFromBlob = (blob) => {
	return new Promise((resolve, reject) => {
		const img = document.createElement("img");
		img.onload = () => {
			resolve(img);
		};
		img.onerror = (e) => {
			reject(e);
		};
		img.src = URL.createObjectURL(blob);
	});
};
/**
* Shared base class for loaders that extracts common logic
*/
var LoaderBaseShared = class extends Loader$1 {
	_renderer;
	_renderTargetOptions;
	_internalLoadingManager;
	_config;
	constructor(config, manager) {
		super(manager);
		this._config = config;
		if (config.renderer) this._renderer = config.renderer;
		this._internalLoadingManager = new LoadingManager();
	}
	setRenderer(renderer) {
		this._renderer = renderer;
		return this;
	}
	setRenderTargetOptions(options) {
		this._renderTargetOptions = options;
		return this;
	}
	prepareQuadRenderer() {
		if (!this._renderer) console.warn("WARNING: A Renderer was not passed to this Loader constructor or in setRenderer, the result of this Loader will need to be converted to a Data Texture with toDataTexture() before you can use it in your renderer.");
		const material = this._config.createMaterial({
			gainMapMax: [
				1,
				1,
				1
			],
			gainMapMin: [
				0,
				0,
				0
			],
			gamma: [
				1,
				1,
				1
			],
			offsetHdr: [
				1,
				1,
				1
			],
			offsetSdr: [
				1,
				1,
				1
			],
			hdrCapacityMax: 1,
			hdrCapacityMin: 0,
			maxDisplayBoost: 1,
			gainMap: new Texture$1(),
			sdr: new Texture$1()
		});
		return this._config.createQuadRenderer({
			width: 16,
			height: 16,
			type: HalfFloatType,
			colorSpace: LinearSRGBColorSpace$2,
			material,
			renderer: this._renderer,
			renderTargetOptions: this._renderTargetOptions
		});
	}
	async processImages(sdrBuffer, gainMapBuffer, imageOrientation) {
		const gainMapBlob = gainMapBuffer ? new Blob([gainMapBuffer], { type: "image/jpeg" }) : void 0;
		const sdrBlob = new Blob([sdrBuffer], { type: "image/jpeg" });
		let sdrImage;
		let gainMapImage;
		let needsFlip = false;
		if (typeof createImageBitmap === "undefined") {
			const res = await Promise.all([gainMapBlob ? getHTMLImageFromBlob(gainMapBlob) : Promise.resolve(void 0), getHTMLImageFromBlob(sdrBlob)]);
			gainMapImage = res[0];
			sdrImage = res[1];
			needsFlip = imageOrientation === "flipY";
		} else {
			const res = await Promise.all([gainMapBlob ? createImageBitmap(gainMapBlob, { imageOrientation: imageOrientation || "flipY" }) : Promise.resolve(void 0), createImageBitmap(sdrBlob, { imageOrientation: imageOrientation || "flipY" })]);
			gainMapImage = res[0];
			sdrImage = res[1];
		}
		return {
			sdrImage,
			gainMapImage,
			needsFlip
		};
	}
	createTextures(sdrImage, gainMapImage, needsFlip) {
		const gainMap = new Texture$1(gainMapImage || new ImageData(2, 2), 300, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, LinearSRGBColorSpace$2);
		gainMap.flipY = needsFlip;
		gainMap.needsUpdate = true;
		const sdr = new Texture$1(sdrImage, 300, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, SRGBColorSpace$2);
		sdr.flipY = needsFlip;
		sdr.needsUpdate = true;
		return {
			gainMap,
			sdr
		};
	}
	updateQuadRenderer(quadRenderer, sdrImage, gainMap, sdr, metadata) {
		quadRenderer.width = sdrImage.width;
		quadRenderer.height = sdrImage.height;
		quadRenderer.material.gainMap = gainMap;
		quadRenderer.material.sdr = sdr;
		quadRenderer.material.gainMapMin = metadata.gainMapMin;
		quadRenderer.material.gainMapMax = metadata.gainMapMax;
		quadRenderer.material.offsetHdr = metadata.offsetHdr;
		quadRenderer.material.offsetSdr = metadata.offsetSdr;
		quadRenderer.material.gamma = metadata.gamma;
		quadRenderer.material.hdrCapacityMin = metadata.hdrCapacityMin;
		quadRenderer.material.hdrCapacityMax = metadata.hdrCapacityMax;
		quadRenderer.material.maxDisplayBoost = Math.pow(2, metadata.hdrCapacityMax);
		quadRenderer.material.needsUpdate = true;
	}
};
//#endregion
//#region node_modules/@monogrid/gainmap-js/dist/decode.js
/**
* @monogrid/gainmap-js v3.4.0
* With ❤️, by MONOGRID 
*/
var vertexShader = `
varying vec2 vUv;

void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
var fragmentShader = `
// min half float value
#define HALF_FLOAT_MIN vec3( -65504, -65504, -65504 )
// max half float value
#define HALF_FLOAT_MAX vec3( 65504, 65504, 65504 )

uniform sampler2D sdr;
uniform sampler2D gainMap;
uniform vec3 gamma;
uniform vec3 offsetHdr;
uniform vec3 offsetSdr;
uniform vec3 gainMapMin;
uniform vec3 gainMapMax;
uniform float weightFactor;

varying vec2 vUv;

void main() {
  vec3 rgb = texture2D( sdr, vUv ).rgb;
  vec3 recovery = texture2D( gainMap, vUv ).rgb;
  vec3 logRecovery = pow( recovery, gamma );
  vec3 logBoost = gainMapMin * ( 1.0 - logRecovery ) + gainMapMax * logRecovery;
  vec3 hdrColor = (rgb + offsetSdr) * exp2( logBoost * weightFactor ) - offsetHdr;
  vec3 clampedHdrColor = max( HALF_FLOAT_MIN, min( HALF_FLOAT_MAX, hdrColor ));
  gl_FragColor = vec4( clampedHdrColor , 1.0 );
}
`;
/**
* A Material which is able to decode the Gainmap into a full HDR Representation
*
* @category Materials
* @group Materials
*/
var GainMapDecoderMaterial = class extends ShaderMaterial {
	_maxDisplayBoost;
	_hdrCapacityMin;
	_hdrCapacityMax;
	/**
	*
	* @param params
	*/
	constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }) {
		super({
			name: "GainMapDecoderMaterial",
			vertexShader,
			fragmentShader,
			uniforms: {
				sdr: { value: sdr },
				gainMap: { value: gainMap },
				gamma: { value: new Vector3(1 / gamma[0], 1 / gamma[1], 1 / gamma[2]) },
				offsetHdr: { value: new Vector3().fromArray(offsetHdr) },
				offsetSdr: { value: new Vector3().fromArray(offsetSdr) },
				gainMapMin: { value: new Vector3().fromArray(gainMapMin) },
				gainMapMax: { value: new Vector3().fromArray(gainMapMax) },
				weightFactor: { value: (Math.log2(maxDisplayBoost) - hdrCapacityMin) / (hdrCapacityMax - hdrCapacityMin) }
			},
			blending: 0,
			depthTest: false,
			depthWrite: false
		});
		this._maxDisplayBoost = maxDisplayBoost;
		this._hdrCapacityMin = hdrCapacityMin;
		this._hdrCapacityMax = hdrCapacityMax;
		this.needsUpdate = true;
		this.uniformsNeedUpdate = true;
	}
	get sdr() {
		return this.uniforms.sdr.value;
	}
	set sdr(value) {
		this.uniforms.sdr.value = value;
	}
	get gainMap() {
		return this.uniforms.gainMap.value;
	}
	set gainMap(value) {
		this.uniforms.gainMap.value = value;
	}
	/**
	* @see {@link GainMapMetadata.offsetHdr}
	*/
	get offsetHdr() {
		return this.uniforms.offsetHdr.value.toArray();
	}
	set offsetHdr(value) {
		this.uniforms.offsetHdr.value.fromArray(value);
	}
	/**
	* @see {@link GainMapMetadata.offsetSdr}
	*/
	get offsetSdr() {
		return this.uniforms.offsetSdr.value.toArray();
	}
	set offsetSdr(value) {
		this.uniforms.offsetSdr.value.fromArray(value);
	}
	/**
	* @see {@link GainMapMetadata.gainMapMin}
	*/
	get gainMapMin() {
		return this.uniforms.gainMapMin.value.toArray();
	}
	set gainMapMin(value) {
		this.uniforms.gainMapMin.value.fromArray(value);
	}
	/**
	* @see {@link GainMapMetadata.gainMapMax}
	*/
	get gainMapMax() {
		return this.uniforms.gainMapMax.value.toArray();
	}
	set gainMapMax(value) {
		this.uniforms.gainMapMax.value.fromArray(value);
	}
	/**
	* @see {@link GainMapMetadata.gamma}
	*/
	get gamma() {
		const g = this.uniforms.gamma.value;
		return [
			1 / g.x,
			1 / g.y,
			1 / g.z
		];
	}
	set gamma(value) {
		const g = this.uniforms.gamma.value;
		g.x = 1 / value[0];
		g.y = 1 / value[1];
		g.z = 1 / value[2];
	}
	/**
	* @see {@link GainMapMetadata.hdrCapacityMin}
	* @remarks Logarithmic space
	*/
	get hdrCapacityMin() {
		return this._hdrCapacityMin;
	}
	set hdrCapacityMin(value) {
		this._hdrCapacityMin = value;
		this.calculateWeight();
	}
	/**
	* @see {@link GainMapMetadata.hdrCapacityMin}
	* @remarks Logarithmic space
	*/
	get hdrCapacityMax() {
		return this._hdrCapacityMax;
	}
	set hdrCapacityMax(value) {
		this._hdrCapacityMax = value;
		this.calculateWeight();
	}
	/**
	* @see {@link GainmapDecodingParameters.maxDisplayBoost}
	* @remarks Non Logarithmic space
	*/
	get maxDisplayBoost() {
		return this._maxDisplayBoost;
	}
	set maxDisplayBoost(value) {
		this._maxDisplayBoost = Math.max(1, Math.min(65504, value));
		this.calculateWeight();
	}
	calculateWeight() {
		const val = (Math.log2(this._maxDisplayBoost) - this._hdrCapacityMin) / (this._hdrCapacityMax - this._hdrCapacityMin);
		this.uniforms.weightFactor.value = Math.max(0, Math.min(1, val));
	}
};
/**
* Base class for WebGL loaders
* @template TUrl - The type of URL used to load resources
*/
var LoaderBaseWebGL = class extends LoaderBaseShared {
	constructor(renderer, manager) {
		super({
			renderer,
			createMaterial: (params) => new GainMapDecoderMaterial(params),
			createQuadRenderer: (params) => new QuadRenderer(params)
		}, manager);
	}
	/**
	* @private
	* @param quadRenderer
	* @param metadata
	* @param sdrBuffer
	* @param gainMapBuffer
	*/
	async render(quadRenderer, metadata, sdrBuffer, gainMapBuffer) {
		const { sdrImage, gainMapImage, needsFlip } = await this.processImages(sdrBuffer, gainMapBuffer, "flipY");
		const { gainMap, sdr } = this.createTextures(sdrImage, gainMapImage, needsFlip);
		this.updateQuadRenderer(quadRenderer, sdrImage, gainMap, sdr, metadata);
		quadRenderer.render();
	}
};
/**
* A Three.js Loader for the gain map format.
*
* @category Loaders
* @group Loaders
*
* @example
* import { GainMapLoader } from '@monogrid/gainmap-js'
* import {
*   EquirectangularReflectionMapping,
*   Mesh,
*   MeshBasicMaterial,
*   PerspectiveCamera,
*   PlaneGeometry,
*   Scene,
*   WebGLRenderer
* } from 'three'
*
* const renderer = new WebGLRenderer()
*
* const loader = new GainMapLoader(renderer)
*   .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
*
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
* // `result` can be used to populate a Texture
*
* const scene = new Scene()
* const mesh = new Mesh(
*   new PlaneGeometry(),
*   new MeshBasicMaterial({ map: result.renderTarget.texture })
* )
* scene.add(mesh)
* renderer.render(scene, new PerspectiveCamera())
*
* // Starting from three.js r159
* // `result.renderTarget.texture` can
* // also be used as Equirectangular scene background
* //
* // it was previously needed to convert it
* // to a DataTexture with `result.toDataTexture()`
* scene.background = result.renderTarget.texture
*
* // result must be manually disposed
* // when you are done using it
* result.dispose()
*
*/
var GainMapLoader = class extends LoaderBaseWebGL {
	/**
	* Loads a gainmap using separate data
	* * sdr image
	* * gain map image
	* * metadata json
	*
	* useful for webp gain maps
	*
	* @param urls An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
	* @param onLoad Load complete callback, will receive the result
	* @param onProgress Progress callback, will receive a `ProgressEvent`
	* @param onError Error callback
	* @returns
	*/
	load([sdrUrl, gainMapUrl, metadataUrl], onLoad, onProgress, onError) {
		const quadRenderer = this.prepareQuadRenderer();
		let sdr;
		let gainMap;
		let metadata;
		const loadCheck = async () => {
			if (sdr && gainMap && metadata) {
				try {
					await this.render(quadRenderer, metadata, sdr, gainMap);
				} catch (error) {
					this.manager.itemError(sdrUrl);
					this.manager.itemError(gainMapUrl);
					this.manager.itemError(metadataUrl);
					if (typeof onError === "function") onError(error);
					quadRenderer.disposeOnDemandRenderer();
					return;
				}
				if (typeof onLoad === "function") onLoad(quadRenderer);
				this.manager.itemEnd(sdrUrl);
				this.manager.itemEnd(gainMapUrl);
				this.manager.itemEnd(metadataUrl);
				quadRenderer.disposeOnDemandRenderer();
			}
		};
		let sdrLengthComputable = true;
		let sdrTotal = 0;
		let sdrLoaded = 0;
		let gainMapLengthComputable = true;
		let gainMapTotal = 0;
		let gainMapLoaded = 0;
		let metadataLengthComputable = true;
		let metadataTotal = 0;
		let metadataLoaded = 0;
		const progressHandler = () => {
			if (typeof onProgress === "function") {
				const total = sdrTotal + gainMapTotal + metadataTotal;
				const loaded = sdrLoaded + gainMapLoaded + metadataLoaded;
				onProgress(new ProgressEvent("progress", {
					lengthComputable: sdrLengthComputable && gainMapLengthComputable && metadataLengthComputable,
					loaded,
					total
				}));
			}
		};
		this.manager.itemStart(sdrUrl);
		this.manager.itemStart(gainMapUrl);
		this.manager.itemStart(metadataUrl);
		const sdrLoader = new FileLoader(this._internalLoadingManager);
		sdrLoader.setResponseType("arraybuffer");
		sdrLoader.setRequestHeader(this.requestHeader);
		sdrLoader.setPath(this.path);
		sdrLoader.setWithCredentials(this.withCredentials);
		sdrLoader.load(sdrUrl, async (buffer) => {
			/* istanbul ignore if
			this condition exists only because of three.js types + strict mode
			*/
			if (typeof buffer === "string") throw new Error("Invalid sdr buffer");
			sdr = buffer;
			await loadCheck();
		}, (e) => {
			sdrLengthComputable = e.lengthComputable;
			sdrLoaded = e.loaded;
			sdrTotal = e.total;
			progressHandler();
		}, (error) => {
			this.manager.itemError(sdrUrl);
			if (typeof onError === "function") onError(error);
		});
		const gainMapLoader = new FileLoader(this._internalLoadingManager);
		gainMapLoader.setResponseType("arraybuffer");
		gainMapLoader.setRequestHeader(this.requestHeader);
		gainMapLoader.setPath(this.path);
		gainMapLoader.setWithCredentials(this.withCredentials);
		gainMapLoader.load(gainMapUrl, async (buffer) => {
			/* istanbul ignore if
			this condition exists only because of three.js types + strict mode
			*/
			if (typeof buffer === "string") throw new Error("Invalid gainmap buffer");
			gainMap = buffer;
			await loadCheck();
		}, (e) => {
			gainMapLengthComputable = e.lengthComputable;
			gainMapLoaded = e.loaded;
			gainMapTotal = e.total;
			progressHandler();
		}, (error) => {
			this.manager.itemError(gainMapUrl);
			if (typeof onError === "function") onError(error);
		});
		const metadataLoader = new FileLoader(this._internalLoadingManager);
		metadataLoader.setRequestHeader(this.requestHeader);
		metadataLoader.setPath(this.path);
		metadataLoader.setWithCredentials(this.withCredentials);
		metadataLoader.load(metadataUrl, async (json) => {
			/* istanbul ignore if
			this condition exists only because of three.js types + strict mode
			*/
			if (typeof json !== "string") throw new Error("Invalid metadata string");
			metadata = JSON.parse(json);
			await loadCheck();
		}, (e) => {
			metadataLengthComputable = e.lengthComputable;
			metadataLoaded = e.loaded;
			metadataTotal = e.total;
			progressHandler();
		}, (error) => {
			this.manager.itemError(metadataUrl);
			if (typeof onError === "function") onError(error);
		});
		return quadRenderer;
	}
};
/**
* A Three.js Loader for a JPEG with embedded gainmap metadata.
*
* @category Loaders
* @group Loaders
*
* @example
* import { HDRJPGLoader } from '@monogrid/gainmap-js'
* import {
*   EquirectangularReflectionMapping,
*   Mesh,
*   MeshBasicMaterial,
*   PerspectiveCamera,
*   PlaneGeometry,
*   Scene,
*   WebGLRenderer
* } from 'three'
*
* const renderer = new WebGLRenderer()
*
* const loader = new HDRJPGLoader(renderer)
*   .setRenderTargetOptions({ mapping: EquirectangularReflectionMapping })
*
* const result = await loader.loadAsync('gainmap.jpeg')
* // `result` can be used to populate a Texture
*
* const scene = new Scene()
* const mesh = new Mesh(
*   new PlaneGeometry(),
*   new MeshBasicMaterial({ map: result.renderTarget.texture })
* )
* scene.add(mesh)
* renderer.render(scene, new PerspectiveCamera())
*
* // Starting from three.js r159
* // `result.renderTarget.texture` can
* // also be used as Equirectangular scene background
* //
* // it was previously needed to convert it
* // to a DataTexture with `result.toDataTexture()`
* scene.background = result.renderTarget.texture
*
* // result must be manually disposed
* // when you are done using it
* result.dispose()
*
*/
var HDRJPGLoader = class extends LoaderBaseWebGL {
	/**
	* Loads a JPEG containing gain map metadata
	* Renders a normal SDR image if gainmap data is not found
	*
	* @param url Path to a JPEG file containing embedded gain map metadata
	* @param onLoad Load complete callback, will receive the result
	* @param onProgress Progress callback, will receive a `ProgressEvent`
	* @param onError Error callback
	* @returns
	*/
	load(url, onLoad, onProgress, onError) {
		const quadRenderer = this.prepareQuadRenderer();
		const loader = new FileLoader(this._internalLoadingManager);
		loader.setResponseType("arraybuffer");
		loader.setRequestHeader(this.requestHeader);
		loader.setPath(this.path);
		loader.setWithCredentials(this.withCredentials);
		this.manager.itemStart(url);
		loader.load(url, async (jpeg) => {
			/* istanbul ignore if
			this condition exists only because of three.js types + strict mode
			*/
			if (typeof jpeg === "string") throw new Error("Invalid buffer, received [string], was expecting [ArrayBuffer]");
			const jpegBuffer = new Uint8Array(jpeg);
			let sdrJPEG;
			let gainMapJPEG;
			let metadata;
			try {
				const extractionResult = await extractGainmapFromJPEG(jpegBuffer);
				sdrJPEG = extractionResult.sdr;
				gainMapJPEG = extractionResult.gainMap;
				metadata = extractionResult.metadata;
			} catch (e) {
				if (e instanceof XMPMetadataNotFoundError || e instanceof GainMapNotFoundError) {
					console.warn(`Failure to reconstruct an HDR image from ${url}: Gain map metadata not found in the file, HDRJPGLoader will render the SDR jpeg`);
					metadata = {
						gainMapMin: [
							0,
							0,
							0
						],
						gainMapMax: [
							1,
							1,
							1
						],
						gamma: [
							1,
							1,
							1
						],
						hdrCapacityMin: 0,
						hdrCapacityMax: 1,
						offsetHdr: [
							0,
							0,
							0
						],
						offsetSdr: [
							0,
							0,
							0
						]
					};
					sdrJPEG = jpegBuffer;
				} else throw e;
			}
			try {
				await this.render(quadRenderer, metadata, sdrJPEG.buffer, gainMapJPEG?.buffer);
			} catch (error) {
				this.manager.itemError(url);
				if (typeof onError === "function") onError(error);
				quadRenderer.disposeOnDemandRenderer();
				return;
			}
			if (typeof onLoad === "function") onLoad(quadRenderer);
			this.manager.itemEnd(url);
			quadRenderer.disposeOnDemandRenderer();
		}, onProgress, (error) => {
			this.manager.itemError(url);
			if (typeof onError === "function") onError(error);
		});
		return quadRenderer;
	}
};
//#endregion
//#region node_modules/@react-three/drei/helpers/environment-assets.js
var presetsObj = {
	apartment: "lebombo_1k.hdr",
	city: "potsdamer_platz_1k.hdr",
	dawn: "kiara_1_dawn_1k.hdr",
	forest: "forest_slope_1k.hdr",
	lobby: "st_fagans_interior_1k.hdr",
	night: "dikhololo_night_1k.hdr",
	park: "rooitou_park_1k.hdr",
	studio: "studio_small_03_1k.hdr",
	sunset: "venice_sunset_1k.hdr",
	warehouse: "empty_warehouse_01_1k.hdr"
};
//#endregion
//#region node_modules/@react-three/drei/core/useEnvironment.js
var CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
var isArray = (arr) => Array.isArray(arr);
var defaultFiles = [
	"/px.png",
	"/nx.png",
	"/py.png",
	"/ny.png",
	"/pz.png",
	"/nz.png"
];
function useEnvironment({ files = defaultFiles, path = "", preset = void 0, colorSpace = void 0, extensions } = {}) {
	if (preset) {
		validatePreset(preset);
		files = presetsObj[preset];
		path = CUBEMAP_ROOT;
	}
	const multiFile = isArray(files);
	const { extension, isCubemap } = getExtension(files);
	const loader = getLoader(extension);
	if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
	const gl = useThree((state) => state.gl);
	(0, import_react.useLayoutEffect)(() => {
		if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
		function clearGainmapTexture() {
			useLoader.clear(loader, multiFile ? [files] : files);
		}
		gl.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
	}, [files, gl.domElement]);
	const loaderResult = useLoader(loader, multiFile ? [files] : files, (loader) => {
		if (extension === "webp" || extension === "jpg" || extension === "jpeg") loader.setRenderer(gl);
		loader.setPath == null || loader.setPath(path);
		if (extensions) extensions(loader);
	});
	let texture = multiFile ? loaderResult[0] : loaderResult;
	if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
		var _renderTarget;
		texture = (_renderTarget = texture.renderTarget) == null ? void 0 : _renderTarget.texture;
	}
	texture.mapping = isCubemap ? 301 : 303;
	texture.colorSpace = colorSpace !== null && colorSpace !== void 0 ? colorSpace : isCubemap ? "srgb" : "srgb-linear";
	return texture;
}
var preloadDefaultOptions = {
	files: defaultFiles,
	path: "",
	preset: void 0,
	extensions: void 0
};
useEnvironment.preload = (preloadOptions) => {
	const options = {
		...preloadDefaultOptions,
		...preloadOptions
	};
	let { files, path = "" } = options;
	const { preset, extensions } = options;
	if (preset) {
		validatePreset(preset);
		files = presetsObj[preset];
		path = CUBEMAP_ROOT;
	}
	const { extension } = getExtension(files);
	if (extension === "webp" || extension === "jpg" || extension === "jpeg") throw new Error("useEnvironment: Preloading gainmaps is not supported");
	const loader = getLoader(extension);
	if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
	useLoader.preload(loader, isArray(files) ? [files] : files, (loader) => {
		loader.setPath == null || loader.setPath(path);
		if (extensions) extensions(loader);
	});
};
var clearDefaultOptins = {
	files: defaultFiles,
	preset: void 0
};
useEnvironment.clear = (clearOptions) => {
	const options = {
		...clearDefaultOptins,
		...clearOptions
	};
	let { files } = options;
	const { preset } = options;
	if (preset) {
		validatePreset(preset);
		files = presetsObj[preset];
	}
	const { extension } = getExtension(files);
	const loader = getLoader(extension);
	if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
	useLoader.clear(loader, isArray(files) ? [files] : files);
};
function validatePreset(preset) {
	if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
}
function getExtension(files) {
	var _firstEntry$split$pop;
	const isCubemap = isArray(files) && files.length === 6;
	const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
	const firstEntry = isArray(files) ? files[0] : files;
	return {
		extension: isCubemap ? "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : (_firstEntry$split$pop = firstEntry.split(".").pop()) == null || (_firstEntry$split$pop = _firstEntry$split$pop.split("?")) == null || (_firstEntry$split$pop = _firstEntry$split$pop.shift()) == null ? void 0 : _firstEntry$split$pop.toLowerCase(),
		isCubemap,
		isGainmap
	};
}
function getLoader(extension) {
	return extension === "cube" ? CubeTextureLoader : extension === "hdr" ? RGBELoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? HDRJPGLoader : extension === "webp" ? GainMapLoader : null;
}
//#endregion
//#region node_modules/@react-three/drei/core/Environment.js
var isRef$1 = (obj) => obj.current && obj.current.isScene;
var resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
	var _target$backgroundRot, _target$backgroundRot2, _target$environmentRo, _target$environmentRo2;
	sceneProps = {
		backgroundBlurriness: 0,
		backgroundIntensity: 1,
		backgroundRotation: [
			0,
			0,
			0
		],
		environmentIntensity: 1,
		environmentRotation: [
			0,
			0,
			0
		],
		...sceneProps
	};
	const target = resolveScene(scene || defaultScene);
	const oldbg = target.background;
	const oldenv = target.environment;
	const oldSceneProps = {
		backgroundBlurriness: target.backgroundBlurriness,
		backgroundIntensity: target.backgroundIntensity,
		backgroundRotation: (_target$backgroundRot = (_target$backgroundRot2 = target.backgroundRotation) == null || _target$backgroundRot2.clone == null ? void 0 : _target$backgroundRot2.clone()) !== null && _target$backgroundRot !== void 0 ? _target$backgroundRot : [
			0,
			0,
			0
		],
		environmentIntensity: target.environmentIntensity,
		environmentRotation: (_target$environmentRo = (_target$environmentRo2 = target.environmentRotation) == null || _target$environmentRo2.clone == null ? void 0 : _target$environmentRo2.clone()) !== null && _target$environmentRo !== void 0 ? _target$environmentRo : [
			0,
			0,
			0
		]
	};
	if (background !== "only") target.environment = texture;
	if (background) target.background = texture;
	applyProps(target, sceneProps);
	return () => {
		if (background !== "only") target.environment = oldenv;
		if (background) target.background = oldbg;
		applyProps(target, oldSceneProps);
	};
}
function EnvironmentMap({ scene, background = false, map, ...config }) {
	const defaultScene = useThree((state) => state.scene);
	import_react.useLayoutEffect(() => {
		if (map) return setEnvProps(background, scene, defaultScene, map, config);
	});
	return null;
}
function EnvironmentCube({ background = false, scene, blur, backgroundBlurriness, backgroundIntensity, backgroundRotation, environmentIntensity, environmentRotation, ...rest }) {
	const texture = useEnvironment(rest);
	const defaultScene = useThree((state) => state.scene);
	import_react.useLayoutEffect(() => {
		return setEnvProps(background, scene, defaultScene, texture, {
			backgroundBlurriness: blur !== null && blur !== void 0 ? blur : backgroundBlurriness,
			backgroundIntensity,
			backgroundRotation,
			environmentIntensity,
			environmentRotation
		});
	});
	import_react.useEffect(() => {
		return () => {
			texture.dispose();
		};
	}, [texture]);
	return null;
}
function EnvironmentPortal({ children, near = .1, far = 1e3, resolution = 256, frames = 1, map, background = false, blur, backgroundBlurriness, backgroundIntensity, backgroundRotation, environmentIntensity, environmentRotation, scene, files, path, preset = void 0, extensions }) {
	const gl = useThree((state) => state.gl);
	const defaultScene = useThree((state) => state.scene);
	const camera = import_react.useRef(null);
	const [virtualScene] = import_react.useState(() => new Scene());
	const fbo = import_react.useMemo(() => {
		const fbo = new WebGLCubeRenderTarget(resolution);
		fbo.texture.type = HalfFloatType;
		return fbo;
	}, [resolution]);
	import_react.useEffect(() => {
		return () => {
			fbo.dispose();
		};
	}, [fbo]);
	import_react.useLayoutEffect(() => {
		if (frames === 1) {
			const autoClear = gl.autoClear;
			gl.autoClear = true;
			camera.current.update(gl, virtualScene);
			gl.autoClear = autoClear;
		}
		return setEnvProps(background, scene, defaultScene, fbo.texture, {
			backgroundBlurriness: blur !== null && blur !== void 0 ? blur : backgroundBlurriness,
			backgroundIntensity,
			backgroundRotation,
			environmentIntensity,
			environmentRotation
		});
	}, [
		children,
		virtualScene,
		fbo.texture,
		scene,
		defaultScene,
		background,
		frames,
		gl
	]);
	let count = 1;
	useFrame(() => {
		if (frames === Infinity || count < frames) {
			const autoClear = gl.autoClear;
			gl.autoClear = true;
			camera.current.update(gl, virtualScene);
			gl.autoClear = autoClear;
			count++;
		}
	});
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, createPortal(/*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children, /*#__PURE__*/ import_react.createElement("cubeCamera", {
		ref: camera,
		args: [
			near,
			far,
			fbo
		]
	}), files || preset ? /*#__PURE__*/ import_react.createElement(EnvironmentCube, {
		background: true,
		files,
		preset,
		path,
		extensions
	}) : map ? /*#__PURE__*/ import_react.createElement(EnvironmentMap, {
		background: true,
		map,
		extensions
	}) : null), virtualScene));
}
function EnvironmentGround(props) {
	var _props$ground, _props$ground2, _scale, _props$ground3;
	const textureDefault = useEnvironment(props);
	const texture = props.map || textureDefault;
	import_react.useMemo(() => extend({ GroundProjectedEnvImpl: GroundProjectedEnv }), []);
	import_react.useEffect(() => {
		return () => {
			textureDefault.dispose();
		};
	}, [textureDefault]);
	const args = import_react.useMemo(() => [texture], [texture]);
	const height = (_props$ground = props.ground) == null ? void 0 : _props$ground.height;
	const radius = (_props$ground2 = props.ground) == null ? void 0 : _props$ground2.radius;
	const scale = (_scale = (_props$ground3 = props.ground) == null ? void 0 : _props$ground3.scale) !== null && _scale !== void 0 ? _scale : 1e3;
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement(EnvironmentMap, _extends$1({}, props, { map: texture })), /*#__PURE__*/ import_react.createElement("groundProjectedEnvImpl", {
		args,
		scale,
		height,
		radius
	}));
}
function Environment(props) {
	return props.ground ? /*#__PURE__*/ import_react.createElement(EnvironmentGround, props) : props.map ? /*#__PURE__*/ import_react.createElement(EnvironmentMap, props) : props.children ? /*#__PURE__*/ import_react.createElement(EnvironmentPortal, props) : /*#__PURE__*/ import_react.createElement(EnvironmentCube, props);
}
//#endregion
//#region node_modules/@react-three/drei/core/ContactShadows.js
var ContactShadows = /* @__PURE__ */ import_react.forwardRef(({ scale = 10, frames = Infinity, opacity = 1, width = 1, height = 1, blur = 1, near = 0, far = 10, resolution = 512, smooth = true, color = "#000000", depthWrite = false, renderOrder, ...props }, fref) => {
	const ref = import_react.useRef(null);
	const scene = useThree((state) => state.scene);
	const gl = useThree((state) => state.gl);
	const shadowCamera = import_react.useRef(null);
	width = width * (Array.isArray(scale) ? scale[0] : scale || 1);
	height = height * (Array.isArray(scale) ? scale[1] : scale || 1);
	const [renderTarget, planeGeometry, depthMaterial, blurPlane, horizontalBlurMaterial, verticalBlurMaterial, renderTargetBlur] = import_react.useMemo(() => {
		const renderTarget = new WebGLRenderTarget(resolution, resolution);
		const renderTargetBlur = new WebGLRenderTarget(resolution, resolution);
		renderTargetBlur.texture.generateMipmaps = renderTarget.texture.generateMipmaps = false;
		const planeGeometry = new PlaneGeometry(width, height).rotateX(Math.PI / 2);
		const blurPlane = new Mesh(planeGeometry);
		const depthMaterial = new MeshDepthMaterial();
		depthMaterial.depthTest = depthMaterial.depthWrite = false;
		depthMaterial.onBeforeCompile = (shader) => {
			shader.uniforms = {
				...shader.uniforms,
				ucolor: { value: new Color(color) }
			};
			shader.fragmentShader = shader.fragmentShader.replace(`void main() {`, `uniform vec3 ucolor;
           void main() {
          `);
			shader.fragmentShader = shader.fragmentShader.replace("vec4( vec3( 1.0 - fragCoordZ ), opacity );", "vec4( ucolor * fragCoordZ * 2.0, ( 1.0 - fragCoordZ ) * 1.0 );");
		};
		const horizontalBlurMaterial = new ShaderMaterial(HorizontalBlurShader);
		const verticalBlurMaterial = new ShaderMaterial(VerticalBlurShader);
		verticalBlurMaterial.depthTest = horizontalBlurMaterial.depthTest = false;
		return [
			renderTarget,
			planeGeometry,
			depthMaterial,
			blurPlane,
			horizontalBlurMaterial,
			verticalBlurMaterial,
			renderTargetBlur
		];
	}, [
		resolution,
		width,
		height,
		scale,
		color
	]);
	const blurShadows = (blur) => {
		blurPlane.visible = true;
		blurPlane.material = horizontalBlurMaterial;
		horizontalBlurMaterial.uniforms.tDiffuse.value = renderTarget.texture;
		horizontalBlurMaterial.uniforms.h.value = blur * 1 / 256;
		gl.setRenderTarget(renderTargetBlur);
		gl.render(blurPlane, shadowCamera.current);
		blurPlane.material = verticalBlurMaterial;
		verticalBlurMaterial.uniforms.tDiffuse.value = renderTargetBlur.texture;
		verticalBlurMaterial.uniforms.v.value = blur * 1 / 256;
		gl.setRenderTarget(renderTarget);
		gl.render(blurPlane, shadowCamera.current);
		blurPlane.visible = false;
	};
	let count = 0;
	let initialBackground;
	let initialOverrideMaterial;
	useFrame(() => {
		if (shadowCamera.current && (frames === Infinity || count < frames)) {
			count++;
			initialBackground = scene.background;
			initialOverrideMaterial = scene.overrideMaterial;
			ref.current.visible = false;
			scene.background = null;
			scene.overrideMaterial = depthMaterial;
			gl.setRenderTarget(renderTarget);
			gl.render(scene, shadowCamera.current);
			blurShadows(blur);
			if (smooth) blurShadows(blur * .4);
			gl.setRenderTarget(null);
			ref.current.visible = true;
			scene.overrideMaterial = initialOverrideMaterial;
			scene.background = initialBackground;
		}
	});
	import_react.useImperativeHandle(fref, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ "rotation-x": Math.PI / 2 }, props, { ref }), /*#__PURE__*/ import_react.createElement("mesh", {
		renderOrder,
		geometry: planeGeometry,
		scale: [
			1,
			-1,
			1
		],
		rotation: [
			-Math.PI / 2,
			0,
			0
		]
	}, /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		map: renderTarget.texture,
		opacity,
		depthWrite
	})), /*#__PURE__*/ import_react.createElement("orthographicCamera", {
		ref: shadowCamera,
		args: [
			-width / 2,
			width / 2,
			height / 2,
			-height / 2,
			near,
			far
		]
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/AccumulativeShadows.js
function isLight(object) {
	return object.isLight;
}
function isGeometry$1(object) {
	return !!object.geometry;
}
var accumulativeContext = /* @__PURE__ */ import_react.createContext(null);
var SoftShadowMaterial = /* @__PURE__ */ shaderMaterial({
	color: /* @__PURE__ */ new Color(),
	blend: 2,
	alphaTest: .75,
	opacity: 0,
	map: null
}, `varying vec2 vUv;
   void main() {
     gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);
     vUv = uv;
   }`, `varying vec2 vUv;
   uniform sampler2D map;
   uniform vec3 color;
   uniform float opacity;
   uniform float alphaTest;
   uniform float blend;
   void main() {
     vec4 sampledDiffuseColor = texture2D(map, vUv);
     gl_FragColor = vec4(color * sampledDiffuseColor.r * blend, max(0.0, (1.0 - (sampledDiffuseColor.r + sampledDiffuseColor.g + sampledDiffuseColor.b) / alphaTest)) * opacity);
     #include 
     #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
   }`);
var AccumulativeShadows = /* @__PURE__ */ import_react.forwardRef(({ children, temporal, frames = 40, limit = Infinity, blend = 20, scale = 10, opacity = 1, alphaTest = .75, color = "black", colorBlend = 2, resolution = 1024, toneMapped = true, ...props }, forwardRef) => {
	extend({ SoftShadowMaterial });
	const gl = useThree((state) => state.gl);
	const scene = useThree((state) => state.scene);
	const camera = useThree((state) => state.camera);
	const invalidate = useThree((state) => state.invalidate);
	const gPlane = import_react.useRef(null);
	const gLights = import_react.useRef(null);
	const [plm] = import_react.useState(() => new ProgressiveLightMap(gl, scene, resolution));
	import_react.useLayoutEffect(() => {
		plm.configure(gPlane.current);
	}, []);
	const api = import_react.useMemo(() => ({
		lights: /* @__PURE__ */ new Map(),
		temporal: !!temporal,
		frames: Math.max(2, frames),
		blend: Math.max(2, frames === Infinity ? blend : frames),
		count: 0,
		getMesh: () => gPlane.current,
		reset: () => {
			plm.clear();
			const material = gPlane.current.material;
			material.opacity = 0;
			material.alphaTest = 0;
			api.count = 0;
		},
		update: (frames = 1) => {
			const material = gPlane.current.material;
			if (!api.temporal) {
				material.opacity = opacity;
				material.alphaTest = alphaTest;
			} else {
				material.opacity = Math.min(opacity, material.opacity + opacity / api.blend);
				material.alphaTest = Math.min(alphaTest, material.alphaTest + alphaTest / api.blend);
			}
			gLights.current.visible = true;
			plm.prepare();
			for (let i = 0; i < frames; i++) {
				api.lights.forEach((light) => light.update());
				plm.update(camera, api.blend);
			}
			gLights.current.visible = false;
			plm.finish();
		}
	}), [
		plm,
		camera,
		scene,
		temporal,
		frames,
		blend,
		opacity,
		alphaTest
	]);
	import_react.useLayoutEffect(() => {
		api.reset();
		if (!api.temporal && api.frames !== Infinity) api.update(api.blend);
	});
	import_react.useImperativeHandle(forwardRef, () => api, [api]);
	useFrame(() => {
		if ((api.temporal || api.frames === Infinity) && api.count < api.frames && api.count < limit) {
			invalidate();
			api.update();
			api.count++;
		}
	});
	return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement("group", {
		traverse: () => null,
		ref: gLights
	}, /*#__PURE__*/ import_react.createElement(accumulativeContext.Provider, { value: api }, children)), /*#__PURE__*/ import_react.createElement("mesh", {
		receiveShadow: true,
		ref: gPlane,
		scale,
		rotation: [
			-Math.PI / 2,
			0,
			0
		]
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("softShadowMaterial", {
		transparent: true,
		depthWrite: false,
		toneMapped,
		color,
		blend: colorBlend,
		map: plm.progressiveLightMap2.texture
	})));
});
var RandomizedLight = /* @__PURE__ */ import_react.forwardRef(({ castShadow = true, bias = .001, mapSize = 512, size = 5, near = .5, far = 500, frames = 1, position = [
	0,
	0,
	0
], radius = 1, amount = 8, intensity = version$1 >= 155 ? Math.PI : 1, ambient = .5, ...props }, forwardRef) => {
	const gLights = import_react.useRef(null);
	const length = new Vector3(...position).length();
	const parent = import_react.useContext(accumulativeContext);
	const update = import_react.useCallback(() => {
		let light;
		if (gLights.current) for (let l = 0; l < gLights.current.children.length; l++) {
			light = gLights.current.children[l];
			if (Math.random() > ambient) light.position.set(position[0] + MathUtils.randFloatSpread(radius), position[1] + MathUtils.randFloatSpread(radius), position[2] + MathUtils.randFloatSpread(radius));
			else {
				let lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2;
				let phi = 2 * Math.PI * Math.random();
				light.position.set(Math.cos(lambda) * Math.cos(phi) * length, Math.abs(Math.cos(lambda) * Math.sin(phi) * length), Math.sin(lambda) * length);
			}
		}
	}, [
		radius,
		ambient,
		length,
		...position
	]);
	const api = import_react.useMemo(() => ({ update }), [update]);
	import_react.useImperativeHandle(forwardRef, () => api, [api]);
	import_react.useLayoutEffect(() => {
		var _parent$lights;
		const group = gLights.current;
		if (parent) (_parent$lights = parent.lights) == null || _parent$lights.set(group.uuid, api);
		return () => {
			var _parent$lights2;
			parent == null || (_parent$lights2 = parent.lights) == null || _parent$lights2.delete(group.uuid);
		};
	}, [parent, api]);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: gLights }, props), Array.from({ length: amount }, (_, index) => /*#__PURE__*/ import_react.createElement("directionalLight", {
		key: index,
		castShadow,
		"shadow-bias": bias,
		"shadow-mapSize": [mapSize, mapSize],
		intensity: intensity / amount
	}, /*#__PURE__*/ import_react.createElement("orthographicCamera", {
		attach: "shadow-camera",
		args: [
			-size,
			size,
			size,
			-size,
			near,
			far
		]
	}))));
});
var ProgressiveLightMap = class {
	constructor(renderer, scene, res = 1024) {
		this.renderer = renderer;
		this.res = res;
		this.scene = scene;
		this.buffer1Active = false;
		this.lights = [];
		this.meshes = [];
		this.object = null;
		this.clearColor = new Color();
		this.clearAlpha = 0;
		const textureParams = {
			type: HalfFloatType,
			magFilter: NearestFilter,
			minFilter: NearestFilter
		};
		this.progressiveLightMap1 = new WebGLRenderTarget(this.res, this.res, textureParams);
		this.progressiveLightMap2 = new WebGLRenderTarget(this.res, this.res, textureParams);
		this.discardMat = new DiscardMaterial();
		this.targetMat = new MeshLambertMaterial({ fog: false });
		this.previousShadowMap = { value: this.progressiveLightMap1.texture };
		this.averagingWindow = { value: 100 };
		this.targetMat.onBeforeCompile = (shader) => {
			shader.vertexShader = "varying vec2 vUv;\n" + shader.vertexShader.slice(0, -1) + "vUv = uv; gl_Position = vec4((uv - 0.5) * 2.0, 1.0, 1.0); }";
			const bodyStart = shader.fragmentShader.indexOf("void main() {");
			shader.fragmentShader = "varying vec2 vUv;\n" + shader.fragmentShader.slice(0, bodyStart) + "uniform sampler2D previousShadowMap;\n	uniform float averagingWindow;\n" + shader.fragmentShader.slice(bodyStart - 1, -1) + `\nvec3 texelOld = texture2D(previousShadowMap, vUv).rgb;
        gl_FragColor.rgb = mix(texelOld, gl_FragColor.rgb, 1.0/ averagingWindow);
      }`;
			shader.uniforms.previousShadowMap = this.previousShadowMap;
			shader.uniforms.averagingWindow = this.averagingWindow;
		};
	}
	clear() {
		this.renderer.getClearColor(this.clearColor);
		this.clearAlpha = this.renderer.getClearAlpha();
		this.renderer.setClearColor("black", 1);
		this.renderer.setRenderTarget(this.progressiveLightMap1);
		this.renderer.clear();
		this.renderer.setRenderTarget(this.progressiveLightMap2);
		this.renderer.clear();
		this.renderer.setRenderTarget(null);
		this.renderer.setClearColor(this.clearColor, this.clearAlpha);
		this.lights = [];
		this.meshes = [];
		this.scene.traverse((object) => {
			if (isGeometry$1(object)) this.meshes.push({
				object,
				material: object.material
			});
			else if (isLight(object)) this.lights.push({
				object,
				intensity: object.intensity
			});
		});
	}
	prepare() {
		this.lights.forEach((light) => light.object.intensity = 0);
		this.meshes.forEach((mesh) => mesh.object.material = this.discardMat);
	}
	finish() {
		this.lights.forEach((light) => light.object.intensity = light.intensity);
		this.meshes.forEach((mesh) => mesh.object.material = mesh.material);
	}
	configure(object) {
		this.object = object;
	}
	update(camera, blendWindow = 100) {
		if (!this.object) return;
		this.averagingWindow.value = blendWindow;
		this.object.material = this.targetMat;
		const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2;
		const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1;
		const oldBg = this.scene.background;
		this.scene.background = null;
		this.renderer.setRenderTarget(activeMap);
		this.previousShadowMap.value = inactiveMap.texture;
		this.buffer1Active = !this.buffer1Active;
		this.renderer.render(this.scene, camera);
		this.renderer.setRenderTarget(null);
		this.scene.background = oldBg;
	}
};
//#endregion
//#region node_modules/@react-three/drei/core/Stage.js
var presets = {
	rembrandt: {
		main: [
			1,
			2,
			1
		],
		fill: [
			-2,
			-.5,
			-2
		]
	},
	portrait: {
		main: [
			-1,
			2,
			.5
		],
		fill: [
			-1,
			.5,
			-1.5
		]
	},
	upfront: {
		main: [
			0,
			2,
			1
		],
		fill: [
			-1,
			.5,
			-1.5
		]
	},
	soft: {
		main: [
			-2,
			4,
			4
		],
		fill: [
			-1,
			.5,
			-1.5
		]
	}
};
function Refit({ radius, adjustCamera }) {
	const api = useBounds();
	import_react.useEffect(() => {
		if (adjustCamera) api.refresh().clip().fit();
	}, [radius, adjustCamera]);
	return null;
}
function Stage({ children, center, adjustCamera = true, intensity = .5, shadows = "contact", environment = "city", preset = "rembrandt", ...props }) {
	var _bias, _normalBias, _size, _offset, _amount, _radius, _ambient, _intensity;
	const config = typeof preset === "string" ? presets[preset] : preset;
	const [{ radius, height }, set] = import_react.useState({
		radius: 0,
		width: 0,
		height: 0,
		depth: 0
	});
	const shadowBias = (_bias = shadows == null ? void 0 : shadows.bias) !== null && _bias !== void 0 ? _bias : -1e-4;
	const normalBias = (_normalBias = shadows == null ? void 0 : shadows.normalBias) !== null && _normalBias !== void 0 ? _normalBias : 0;
	const shadowSize = (_size = shadows == null ? void 0 : shadows.size) !== null && _size !== void 0 ? _size : 1024;
	const shadowOffset = (_offset = shadows == null ? void 0 : shadows.offset) !== null && _offset !== void 0 ? _offset : 0;
	const contactShadow = shadows === "contact" || (shadows == null ? void 0 : shadows.type) === "contact";
	const accumulativeShadow = shadows === "accumulative" || (shadows == null ? void 0 : shadows.type) === "accumulative";
	const shadowSpread = { ...typeof shadows === "object" ? shadows : {} };
	const environmentProps = !environment ? null : typeof environment === "string" ? { preset: environment } : environment;
	const onCentered = import_react.useCallback((props) => {
		const { width, height, depth, boundingSphere } = props;
		set({
			radius: boundingSphere.radius,
			width,
			height,
			depth
		});
		if (center != null && center.onCentered) center.onCentered(props);
	}, []);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("ambientLight", { intensity: intensity / 3 }), /*#__PURE__*/ import_react.createElement("spotLight", {
		penumbra: 1,
		position: [
			config.main[0] * radius,
			config.main[1] * radius,
			config.main[2] * radius
		],
		intensity: intensity * 2,
		castShadow: !!shadows,
		"shadow-bias": shadowBias,
		"shadow-normalBias": normalBias,
		"shadow-mapSize": shadowSize
	}), /*#__PURE__*/ import_react.createElement("pointLight", {
		position: [
			config.fill[0] * radius,
			config.fill[1] * radius,
			config.fill[2] * radius
		],
		intensity
	}), /*#__PURE__*/ import_react.createElement(Bounds, _extends$1({
		fit: !!adjustCamera,
		clip: !!adjustCamera,
		margin: Number(adjustCamera),
		observe: true
	}, props), /*#__PURE__*/ import_react.createElement(Refit, {
		radius,
		adjustCamera
	}), /*#__PURE__*/ import_react.createElement(Center, _extends$1({}, center, {
		position: [
			0,
			shadowOffset / 2,
			0
		],
		onCentered
	}), children)), /*#__PURE__*/ import_react.createElement("group", { position: [
		0,
		-height / 2 - shadowOffset / 2,
		0
	] }, contactShadow && /*#__PURE__*/ import_react.createElement(ContactShadows, _extends$1({
		scale: radius * 4,
		far: radius,
		blur: 2
	}, shadowSpread)), accumulativeShadow && /*#__PURE__*/ import_react.createElement(AccumulativeShadows, _extends$1({
		temporal: true,
		frames: 100,
		alphaTest: .9,
		toneMapped: true,
		scale: radius * 4
	}, shadowSpread), /*#__PURE__*/ import_react.createElement(RandomizedLight, {
		amount: (_amount = shadowSpread.amount) !== null && _amount !== void 0 ? _amount : 8,
		radius: (_radius = shadowSpread.radius) !== null && _radius !== void 0 ? _radius : radius,
		ambient: (_ambient = shadowSpread.ambient) !== null && _ambient !== void 0 ? _ambient : .5,
		intensity: (_intensity = shadowSpread.intensity) !== null && _intensity !== void 0 ? _intensity : 1,
		position: [
			config.main[0] * radius,
			config.main[1] * radius,
			config.main[2] * radius
		],
		size: radius * 4,
		bias: -shadowBias,
		mapSize: shadowSize
	}))), environment && /*#__PURE__*/ import_react.createElement(Environment, environmentProps));
}
//#endregion
//#region node_modules/@react-three/drei/core/Backdrop.js
var easeInExpo = (x) => x === 0 ? 0 : Math.pow(2, 10 * x - 10);
function Backdrop({ children, floor = .25, segments = 20, receiveShadow, ...props }) {
	const ref = import_react.useRef(null);
	import_react.useLayoutEffect(() => {
		let i = 0;
		const offset = segments / segments / 2;
		const position = ref.current.attributes.position;
		for (let x = 0; x < segments + 1; x++) for (let y = 0; y < segments + 1; y++) position.setXYZ(i++, x / segments - offset + (x === 0 ? -floor : 0), y / segments - offset, easeInExpo(x / segments));
		position.needsUpdate = true;
		ref.current.computeVertexNormals();
	}, [segments, floor]);
	return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement("mesh", {
		receiveShadow,
		rotation: [
			-Math.PI / 2,
			0,
			Math.PI / 2
		]
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", {
		ref,
		args: [
			1,
			1,
			segments,
			segments
		]
	}), children));
}
//#endregion
//#region node_modules/@react-three/drei/core/Shadow.js
var Shadow = /* @__PURE__ */ import_react.forwardRef(({ fog = false, renderOrder, depthWrite = false, colorStop = 0, color = "black", opacity = .5, ...props }, ref) => {
	const canvas = import_react.useMemo(() => {
		const canvas = document.createElement("canvas");
		canvas.width = 128;
		canvas.height = 128;
		const context = canvas.getContext("2d");
		const gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
		gradient.addColorStop(colorStop, new Color(color).getStyle());
		gradient.addColorStop(1, "rgba(0,0,0,0)");
		context.fillStyle = gradient;
		context.fillRect(0, 0, canvas.width, canvas.height);
		return canvas;
	}, [color, colorStop]);
	return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({
		renderOrder,
		ref,
		"rotation-x": -Math.PI / 2
	}, props), /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		opacity,
		fog,
		depthWrite,
		side: 2
	}, /*#__PURE__*/ import_react.createElement("canvasTexture", {
		attach: "map",
		args: [canvas]
	})));
});
//#endregion
//#region node_modules/@react-three/drei/core/Caustics.js
function createNormalMaterial(side = 0) {
	const viewMatrix = { value: new Matrix4() };
	return Object.assign(new MeshNormalMaterial({ side }), {
		viewMatrix,
		onBeforeCompile: (shader) => {
			shader.uniforms.viewMatrix = viewMatrix;
			shader.fragmentShader = `vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {
           return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );
         }\n` + shader.fragmentShader.replace("#include ", `#include 
           normal = inverseTransformDirection( normal, viewMatrix );\n`);
		}
	});
}
var CausticsProjectionMaterial = /* @__PURE__ */ shaderMaterial({
	causticsTexture: null,
	causticsTextureB: null,
	color: /* @__PURE__ */ new Color(),
	lightProjMatrix: /* @__PURE__ */ new Matrix4(),
	lightViewMatrix: /* @__PURE__ */ new Matrix4()
}, `varying vec3 vWorldPosition;
   void main() {
     gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);
     vec4 worldPosition = modelMatrix * vec4(position, 1.);
     vWorldPosition = worldPosition.xyz;
   }`, `varying vec3 vWorldPosition;
  uniform vec3 color;
  uniform sampler2D causticsTexture;
  uniform sampler2D causticsTextureB;
  uniform mat4 lightProjMatrix;
  uniform mat4 lightViewMatrix;
   void main() {
    // Apply caustics
    vec4 lightSpacePos = lightProjMatrix * lightViewMatrix * vec4(vWorldPosition, 1.0);
    lightSpacePos.xyz /= lightSpacePos.w;
    lightSpacePos.xyz = lightSpacePos.xyz * 0.5 + 0.5;
    vec3 front = texture2D(causticsTexture, lightSpacePos.xy).rgb;
    vec3 back = texture2D(causticsTextureB, lightSpacePos.xy).rgb;
    gl_FragColor = vec4((front + back) * color, 1.0);
    #include 
    #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
   }`);
var CausticsMaterial = /* @__PURE__ */ shaderMaterial({
	cameraMatrixWorld: /* @__PURE__ */ new Matrix4(),
	cameraProjectionMatrixInv: /* @__PURE__ */ new Matrix4(),
	normalTexture: null,
	depthTexture: null,
	lightDir: /* @__PURE__ */ new Vector3(0, 1, 0),
	lightPlaneNormal: /* @__PURE__ */ new Vector3(0, 1, 0),
	lightPlaneConstant: 0,
	near: .1,
	far: 100,
	modelMatrix: /* @__PURE__ */ new Matrix4(),
	worldRadius: 1 / 40,
	ior: 1.1,
	bounces: 0,
	resolution: 1024,
	size: 10,
	intensity: .5
}, `
  varying vec2 vUv;
  void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }`, `
  uniform mat4 cameraMatrixWorld;
  uniform mat4 cameraProjectionMatrixInv;
  uniform vec3 lightDir;
  uniform vec3 lightPlaneNormal;
  uniform float lightPlaneConstant;
  uniform float near;
  uniform float far;
  uniform float time;
  uniform float worldRadius;
  uniform float resolution;
  uniform float size;
  uniform float intensity;
  uniform float ior;
  precision highp isampler2D;
  precision highp usampler2D;
  uniform sampler2D normalTexture;
  uniform sampler2D depthTexture;
  uniform float bounces;
  varying vec2 vUv;
  vec3 WorldPosFromDepth(float depth, vec2 coord) {
    float z = depth * 2.0 - 1.0;
    vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
    vec4 viewSpacePosition = cameraProjectionMatrixInv * clipSpacePosition;
    // Perspective division
    viewSpacePosition /= viewSpacePosition.w;
    vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;
    return worldSpacePosition.xyz;
  }
  float sdPlane( vec3 p, vec3 n, float h ) {
    // n must be normalized
    return dot(p,n) + h;
  }
  float planeIntersect( vec3 ro, vec3 rd, vec4 p ) {
    return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);
  }
  vec3 totalInternalReflection(vec3 ro, vec3 rd, vec3 pos, vec3 normal, float ior, out vec3 rayOrigin, out vec3 rayDirection) {
    rayOrigin = ro;
    rayDirection = rd;
    rayDirection = refract(rayDirection, normal, 1.0 / ior);
    rayOrigin = pos + rayDirection * 0.1;
    return rayDirection;
  }
  void main() {
    // Each sample consists of random offset in the x and y direction
    float caustic = 0.0;
    float causticTexelSize = (1.0 / resolution) * size * 2.0;
    float texelsNeeded = worldRadius / causticTexelSize;
    float sampleRadius = texelsNeeded / resolution;
    float sum = 0.0;
    if (texture2D(depthTexture, vUv).x == 1.0) {
      gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
      return;
    }
    vec2 offset1 = vec2(-0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);
    vec2 offset2 = vec2(-0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);
    vec2 offset3 = vec2(0.5, 0.5);//vec2(rand() - 0.5, rand() - 0.5);
    vec2 offset4 = vec2(0.5, -0.5);//vec2(rand() - 0.5, rand() - 0.5);
    vec2 uv1 = vUv + offset1 * sampleRadius;
    vec2 uv2 = vUv + offset2 * sampleRadius;
    vec2 uv3 = vUv + offset3 * sampleRadius;
    vec2 uv4 = vUv + offset4 * sampleRadius;
    vec3 normal1 = texture2D(normalTexture, uv1, -10.0).rgb * 2.0 - 1.0;
    vec3 normal2 = texture2D(normalTexture, uv2, -10.0).rgb * 2.0 - 1.0;
    vec3 normal3 = texture2D(normalTexture, uv3, -10.0).rgb * 2.0 - 1.0;
    vec3 normal4 = texture2D(normalTexture, uv4, -10.0).rgb * 2.0 - 1.0;
    float depth1 = texture2D(depthTexture, uv1, -10.0).x;
    float depth2 = texture2D(depthTexture, uv2, -10.0).x;
    float depth3 = texture2D(depthTexture, uv3, -10.0).x;
    float depth4 = texture2D(depthTexture, uv4, -10.0).x;
    // Sanity check the depths
    if (depth1 == 1.0 || depth2 == 1.0 || depth3 == 1.0 || depth4 == 1.0) {
      gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
      return;
    }
    vec3 pos1 = WorldPosFromDepth(depth1, uv1);
    vec3 pos2 = WorldPosFromDepth(depth2, uv2);
    vec3 pos3 = WorldPosFromDepth(depth3, uv3);
    vec3 pos4 = WorldPosFromDepth(depth4, uv4);
    vec3 originPos1 = WorldPosFromDepth(0.0, uv1);
    vec3 originPos2 = WorldPosFromDepth(0.0, uv2);
    vec3 originPos3 = WorldPosFromDepth(0.0, uv3);
    vec3 originPos4 = WorldPosFromDepth(0.0, uv4);
    vec3 endPos1, endPos2, endPos3, endPos4;
    vec3 endDir1, endDir2, endDir3, endDir4;
    totalInternalReflection(originPos1, lightDir, pos1, normal1, ior, endPos1, endDir1);
    totalInternalReflection(originPos2, lightDir, pos2, normal2, ior, endPos2, endDir2);
    totalInternalReflection(originPos3, lightDir, pos3, normal3, ior, endPos3, endDir3);
    totalInternalReflection(originPos4, lightDir, pos4, normal4, ior, endPos4, endDir4);
    float lightPosArea = length(cross(originPos2 - originPos1, originPos3 - originPos1)) + length(cross(originPos3 - originPos1, originPos4 - originPos1));
    float t1 = planeIntersect(endPos1, endDir1, vec4(lightPlaneNormal, lightPlaneConstant));
    float t2 = planeIntersect(endPos2, endDir2, vec4(lightPlaneNormal, lightPlaneConstant));
    float t3 = planeIntersect(endPos3, endDir3, vec4(lightPlaneNormal, lightPlaneConstant));
    float t4 = planeIntersect(endPos4, endDir4, vec4(lightPlaneNormal, lightPlaneConstant));
    vec3 finalPos1 = endPos1 + endDir1 * t1;
    vec3 finalPos2 = endPos2 + endDir2 * t2;
    vec3 finalPos3 = endPos3 + endDir3 * t3;
    vec3 finalPos4 = endPos4 + endDir4 * t4;
    float finalArea = length(cross(finalPos2 - finalPos1, finalPos3 - finalPos1)) + length(cross(finalPos3 - finalPos1, finalPos4 - finalPos1));
    caustic += intensity * (lightPosArea / finalArea);
    // Calculate the area of the triangle in light spaces
    gl_FragColor = vec4(vec3(max(caustic, 0.0)), 1.0);
  }`);
var NORMALPROPS = {
	depth: true,
	minFilter: LinearFilter,
	magFilter: LinearFilter,
	type: UnsignedByteType
};
var CAUSTICPROPS = {
	minFilter: LinearMipmapLinearFilter,
	magFilter: LinearFilter,
	type: FloatType,
	generateMipmaps: true
};
var Caustics = /* @__PURE__ */ import_react.forwardRef(({ debug, children, frames = 1, ior = 1.1, color = "white", causticsOnly = false, backside = false, backsideIOR = 1.1, worldRadius = .3125, intensity = .05, resolution = 2024, lightSource = [
	5,
	5,
	5
], ...props }, fref) => {
	extend({ CausticsProjectionMaterial });
	const ref = import_react.useRef(null);
	const camera = import_react.useRef(null);
	const scene = import_react.useRef(null);
	const plane = import_react.useRef(null);
	const gl = useThree((state) => state.gl);
	const helper = useHelper(debug && camera, CameraHelper);
	const normalTarget = useFBO(resolution, resolution, NORMALPROPS);
	const normalTargetB = useFBO(resolution, resolution, NORMALPROPS);
	const causticsTarget = useFBO(resolution, resolution, CAUSTICPROPS);
	const causticsTargetB = useFBO(resolution, resolution, CAUSTICPROPS);
	const [normalMat] = import_react.useState(() => createNormalMaterial());
	const [normalMatB] = import_react.useState(() => createNormalMaterial(1));
	const [causticsMaterial] = import_react.useState(() => new CausticsMaterial());
	const [causticsQuad] = import_react.useState(() => new FullScreenQuad(causticsMaterial));
	import_react.useLayoutEffect(() => {
		ref.current.updateWorldMatrix(false, true);
	});
	let count = 0;
	const v = new Vector3();
	const lpF = new Frustum();
	const lpM = new Matrix4();
	const lpP = new Plane$1();
	const lightDir = new Vector3();
	const lightDirInv = new Vector3();
	const bounds = new Box3();
	const focusPos = new Vector3();
	const boundsVertices = [];
	const worldVerts = [];
	const projectedVerts = [];
	const lightDirs = [];
	const cameraPos = new Vector3();
	for (let i = 0; i < 8; i++) {
		boundsVertices.push(new Vector3());
		worldVerts.push(new Vector3());
		projectedVerts.push(new Vector3());
		lightDirs.push(new Vector3());
	}
	useFrame(() => {
		if (frames === Infinity || count++ < frames) {
			var _scene$current$parent, _helper$current;
			if (Array.isArray(lightSource)) lightDir.fromArray(lightSource).normalize();
			else lightDir.copy(ref.current.worldToLocal(lightSource.current.getWorldPosition(v)).normalize());
			lightDirInv.copy(lightDir).multiplyScalar(-1);
			(_scene$current$parent = scene.current.parent) == null || _scene$current$parent.matrixWorld.identity();
			bounds.setFromObject(scene.current, true);
			boundsVertices[0].set(bounds.min.x, bounds.min.y, bounds.min.z);
			boundsVertices[1].set(bounds.min.x, bounds.min.y, bounds.max.z);
			boundsVertices[2].set(bounds.min.x, bounds.max.y, bounds.min.z);
			boundsVertices[3].set(bounds.min.x, bounds.max.y, bounds.max.z);
			boundsVertices[4].set(bounds.max.x, bounds.min.y, bounds.min.z);
			boundsVertices[5].set(bounds.max.x, bounds.min.y, bounds.max.z);
			boundsVertices[6].set(bounds.max.x, bounds.max.y, bounds.min.z);
			boundsVertices[7].set(bounds.max.x, bounds.max.y, bounds.max.z);
			for (let i = 0; i < 8; i++) worldVerts[i].copy(boundsVertices[i]);
			bounds.getCenter(focusPos);
			boundsVertices.map((v) => v.sub(focusPos));
			const lightPlane = lpP.set(lightDirInv, 0);
			boundsVertices.map((v, i) => lightPlane.projectPoint(v, projectedVerts[i]));
			const centralVert = projectedVerts.reduce((a, b) => a.add(b), v.set(0, 0, 0)).divideScalar(projectedVerts.length);
			const radius = projectedVerts.map((v) => v.distanceTo(centralVert)).reduce((a, b) => Math.max(a, b));
			const dirLength = boundsVertices.map((x) => x.dot(lightDir)).reduce((a, b) => Math.max(a, b));
			camera.current.position.copy(cameraPos.copy(lightDir).multiplyScalar(dirLength).add(focusPos));
			camera.current.lookAt(scene.current.localToWorld(focusPos));
			const dirMatrix = lpM.lookAt(camera.current.position, focusPos, v.set(0, 1, 0));
			camera.current.left = -radius;
			camera.current.right = radius;
			camera.current.top = radius;
			camera.current.bottom = -radius;
			const yOffset = v.set(0, radius, 0).applyMatrix4(dirMatrix);
			const yTime = (camera.current.position.y + yOffset.y) / lightDir.y;
			camera.current.near = .1;
			camera.current.far = yTime;
			camera.current.updateProjectionMatrix();
			camera.current.updateMatrixWorld();
			const groundProjectedCoords = worldVerts.map((v, i) => v.add(lightDirs[i].copy(lightDir).multiplyScalar(-v.y / lightDir.y)));
			const centerPos = groundProjectedCoords.reduce((a, b) => a.add(b), v.set(0, 0, 0)).divideScalar(groundProjectedCoords.length);
			const maxSize = 2 * groundProjectedCoords.map((v) => Math.hypot(v.x - centerPos.x, v.z - centerPos.z)).reduce((a, b) => Math.max(a, b));
			plane.current.scale.setScalar(maxSize);
			plane.current.position.copy(centerPos);
			if (debug) (_helper$current = helper.current) == null || _helper$current.update();
			normalMatB.viewMatrix.value = normalMat.viewMatrix.value = camera.current.matrixWorldInverse;
			const dirLightNearPlane = lpF.setFromProjectionMatrix(lpM.multiplyMatrices(camera.current.projectionMatrix, camera.current.matrixWorldInverse)).planes[4];
			causticsMaterial.cameraMatrixWorld = camera.current.matrixWorld;
			causticsMaterial.cameraProjectionMatrixInv = camera.current.projectionMatrixInverse;
			causticsMaterial.lightDir = lightDirInv;
			causticsMaterial.lightPlaneNormal = dirLightNearPlane.normal;
			causticsMaterial.lightPlaneConstant = dirLightNearPlane.constant;
			causticsMaterial.near = camera.current.near;
			causticsMaterial.far = camera.current.far;
			causticsMaterial.resolution = resolution;
			causticsMaterial.size = radius;
			causticsMaterial.intensity = intensity;
			causticsMaterial.worldRadius = worldRadius;
			scene.current.visible = true;
			gl.setRenderTarget(normalTarget);
			gl.clear();
			scene.current.overrideMaterial = normalMat;
			gl.render(scene.current, camera.current);
			gl.setRenderTarget(normalTargetB);
			gl.clear();
			if (backside) {
				scene.current.overrideMaterial = normalMatB;
				gl.render(scene.current, camera.current);
			}
			scene.current.overrideMaterial = null;
			causticsMaterial.ior = ior;
			plane.current.material.lightProjMatrix = camera.current.projectionMatrix;
			plane.current.material.lightViewMatrix = camera.current.matrixWorldInverse;
			causticsMaterial.normalTexture = normalTarget.texture;
			causticsMaterial.depthTexture = normalTarget.depthTexture;
			gl.setRenderTarget(causticsTarget);
			gl.clear();
			causticsQuad.render(gl);
			causticsMaterial.ior = backsideIOR;
			causticsMaterial.normalTexture = normalTargetB.texture;
			causticsMaterial.depthTexture = normalTargetB.depthTexture;
			gl.setRenderTarget(causticsTargetB);
			gl.clear();
			if (backside) causticsQuad.render(gl);
			gl.setRenderTarget(null);
			if (causticsOnly) scene.current.visible = false;
		}
	});
	import_react.useImperativeHandle(fref, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props), /*#__PURE__*/ import_react.createElement("scene", { ref: scene }, /*#__PURE__*/ import_react.createElement("orthographicCamera", {
		ref: camera,
		up: [
			0,
			1,
			0
		]
	}), children), /*#__PURE__*/ import_react.createElement("mesh", {
		renderOrder: 2,
		ref: plane,
		"rotation-x": -Math.PI / 2
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("causticsProjectionMaterial", {
		transparent: true,
		color,
		causticsTexture: causticsTarget.texture,
		causticsTextureB: causticsTargetB.texture,
		blending: 5,
		blendSrc: 201,
		blendDst: 204,
		depthWrite: false
	}), debug && /*#__PURE__*/ import_react.createElement(Edges, null, /*#__PURE__*/ import_react.createElement("lineBasicMaterial", {
		color: "#ffff00",
		toneMapped: false
	}))));
});
//#endregion
//#region node_modules/@react-three/drei/materials/SpotLightMaterial.js
var SpotLightMaterial = class extends ShaderMaterial {
	constructor() {
		super({
			uniforms: {
				depth: { value: null },
				opacity: { value: 1 },
				attenuation: { value: 2.5 },
				anglePower: { value: 12 },
				spotPosition: { value: new Vector3(0, 0, 0) },
				lightColor: { value: new Color("white") },
				cameraNear: { value: 0 },
				cameraFar: { value: 1 },
				resolution: { value: new Vector2(0, 0) }
			},
			transparent: true,
			depthWrite: false,
			vertexShader: `
        varying vec3 vNormal;
        varying float vViewZ;
        varying float vIntensity;
        uniform vec3 spotPosition;
        uniform float attenuation;

        #include 
        #include 

        void main() {
          // compute intensity
          vNormal = normalize(normalMatrix * normal);
          vec4 worldPosition = modelMatrix * vec4(position, 1);
          vec4 viewPosition = viewMatrix * worldPosition;
          vViewZ = viewPosition.z;

          vIntensity = 1.0 - saturate(distance(worldPosition.xyz, spotPosition) / attenuation);

          gl_Position = projectionMatrix * viewPosition;

          #include 
        }
      `,
			fragmentShader: `
        varying vec3 vNormal;
        varying float vViewZ;
        varying float vIntensity;

        uniform vec3 lightColor;
        uniform float anglePower;
        uniform sampler2D depth;
        uniform vec2 resolution;
        uniform float cameraNear;
        uniform float cameraFar;
        uniform float opacity;

        #include 
        #include 

        float readDepth(sampler2D depthSampler, vec2 uv) {
          float fragCoordZ = texture(depthSampler, uv).r;

          // https://github.com/mrdoob/three.js/issues/23072
          #ifdef USE_LOGDEPTHBUF
            float viewZ = 1.0 - exp2(fragCoordZ * log(cameraFar + 1.0) / log(2.0));
          #else
            float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
          #endif

          return viewZ;
        }

        void main() {
          #include 

          vec3 normal = vec3(vNormal.x, vNormal.y, abs(vNormal.z));
          float angleIntensity = pow(dot(normal, vec3(0, 0, 1)), anglePower);
          float intensity = vIntensity * angleIntensity;

          // fades when z is close to sampled depth, meaning the cone is intersecting existing geometry
          bool isSoft = resolution[0] > 0.0 && resolution[1] > 0.0;
          if (isSoft) {
            vec2 uv = gl_FragCoord.xy / resolution;
            intensity *= smoothstep(0.0, 1.0, vViewZ - readDepth(depth, uv));
          }

          gl_FragColor = vec4(lightColor, intensity * opacity);

          #include 
          #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
        }
      `
		});
	}
};
//#endregion
//#region node_modules/@react-three/drei/helpers/glsl/DefaultSpotlightShadowShadows.glsl.js
var SpotlightShadowShader = "#define GLSLIFY 1\nvarying vec2 vUv;uniform sampler2D uShadowMap;uniform float uTime;void main(){vec3 color=texture2D(uShadowMap,vUv).xyz;gl_FragColor=vec4(color,1.);}";
//#endregion
//#region node_modules/@react-three/drei/core/SpotLight.js
var isSpotLight = (child) => {
	return child == null ? void 0 : child.isSpotLight;
};
function VolumetricMesh({ opacity = 1, radiusTop, radiusBottom, depthBuffer, color = "white", distance = 5, angle = .15, attenuation = 5, anglePower = 5 }) {
	const mesh = import_react.useRef(null);
	const size = useThree((state) => state.size);
	const camera = useThree((state) => state.camera);
	const dpr = useThree((state) => state.viewport.dpr);
	const [material] = import_react.useState(() => new SpotLightMaterial());
	const [vec] = import_react.useState(() => new Vector3());
	radiusTop = radiusTop === void 0 ? .1 : radiusTop;
	radiusBottom = radiusBottom === void 0 ? angle * 7 : radiusBottom;
	useFrame(() => {
		material.uniforms.spotPosition.value.copy(mesh.current.getWorldPosition(vec));
		mesh.current.lookAt(mesh.current.parent.target.getWorldPosition(vec));
	});
	const geom = import_react.useMemo(() => {
		const geometry = new CylinderGeometry(radiusTop, radiusBottom, distance, 128, 64, true);
		geometry.applyMatrix4(new Matrix4().makeTranslation(0, -distance / 2, 0));
		geometry.applyMatrix4(new Matrix4().makeRotationX(-Math.PI / 2));
		return geometry;
	}, [
		distance,
		radiusTop,
		radiusBottom
	]);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("mesh", {
		ref: mesh,
		geometry: geom,
		raycast: () => null
	}, /*#__PURE__*/ import_react.createElement("primitive", {
		object: material,
		attach: "material",
		"uniforms-opacity-value": opacity,
		"uniforms-lightColor-value": color,
		"uniforms-attenuation-value": attenuation,
		"uniforms-anglePower-value": anglePower,
		"uniforms-depth-value": depthBuffer,
		"uniforms-cameraNear-value": camera.near,
		"uniforms-cameraFar-value": camera.far,
		"uniforms-resolution-value": depthBuffer ? [size.width * dpr, size.height * dpr] : [0, 0]
	})));
}
function useCommon(spotlight, mesh, width, height, distance) {
	const [[pos, dir]] = import_react.useState(() => [new Vector3(), new Vector3()]);
	import_react.useLayoutEffect(() => {
		if (isSpotLight(spotlight.current)) {
			spotlight.current.shadow.mapSize.set(width, height);
			spotlight.current.shadow.needsUpdate = true;
		} else throw new Error("SpotlightShadow must be a child of a SpotLight");
	}, [
		spotlight,
		width,
		height
	]);
	useFrame(() => {
		if (!spotlight.current) return;
		const A = spotlight.current.position;
		const B = spotlight.current.target.position;
		dir.copy(B).sub(A);
		var len = dir.length();
		dir.normalize().multiplyScalar(len * distance);
		pos.copy(A).add(dir);
		mesh.current.position.copy(pos);
		mesh.current.lookAt(spotlight.current.target.position);
	});
}
function SpotlightShadowWithShader({ distance = .4, alphaTest = .5, map, shader = SpotlightShadowShader, width = 512, height = 512, scale = 1, children, ...rest }) {
	const mesh = import_react.useRef(null);
	const spotlight = rest.spotlightRef;
	const debug = rest.debug;
	useCommon(spotlight, mesh, width, height, distance);
	const renderTarget = import_react.useMemo(() => new WebGLRenderTarget(width, height, {
		format: RGBAFormat,
		stencilBuffer: false
	}), [width, height]);
	const uniforms = import_react.useRef({
		uShadowMap: { value: map },
		uTime: { value: 0 }
	});
	import_react.useEffect(() => void (uniforms.current.uShadowMap.value = map), [map]);
	const fsQuad = import_react.useMemo(() => new FullScreenQuad(new ShaderMaterial({
		uniforms: uniforms.current,
		vertexShader: `
          varying vec2 vUv;

          void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
          `,
		fragmentShader: shader
	})), [shader]);
	import_react.useEffect(() => () => {
		fsQuad.material.dispose();
		fsQuad.dispose();
	}, [fsQuad]);
	import_react.useEffect(() => () => renderTarget.dispose(), [renderTarget]);
	useFrame(({ gl }, dt) => {
		uniforms.current.uTime.value += dt;
		gl.setRenderTarget(renderTarget);
		fsQuad.render(gl);
		gl.setRenderTarget(null);
	});
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("mesh", {
		ref: mesh,
		scale,
		castShadow: true
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		side: 2,
		alphaTest,
		alphaMap: renderTarget.texture,
		"alphaMap-wrapS": RepeatWrapping,
		"alphaMap-wrapT": RepeatWrapping,
		opacity: debug ? 1 : 0
	}, children)));
}
function SpotlightShadowWithoutShader({ distance = .4, alphaTest = .5, map, width = 512, height = 512, scale, children, ...rest }) {
	const mesh = import_react.useRef(null);
	const spotlight = rest.spotlightRef;
	const debug = rest.debug;
	useCommon(spotlight, mesh, width, height, distance);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("mesh", {
		ref: mesh,
		scale,
		castShadow: true
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		side: 2,
		alphaTest,
		alphaMap: map,
		"alphaMap-wrapS": RepeatWrapping,
		"alphaMap-wrapT": RepeatWrapping,
		opacity: debug ? 1 : 0
	}, children)));
}
function SpotLightShadow(props) {
	if (props.shader) return /*#__PURE__*/ import_react.createElement(SpotlightShadowWithShader, props);
	return /*#__PURE__*/ import_react.createElement(SpotlightShadowWithoutShader, props);
}
var SpotLight = /*#__PURE__*/ import_react.forwardRef(({ opacity = 1, radiusTop, radiusBottom, depthBuffer, color = "white", distance = 5, angle = .15, attenuation = 5, anglePower = 5, volumetric = true, debug = false, children, ...props }, ref) => {
	const spotlight = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => spotlight.current, []);
	return /*#__PURE__*/ import_react.createElement("group", null, debug && spotlight.current && /*#__PURE__*/ import_react.createElement("spotLightHelper", { args: [spotlight.current] }), /*#__PURE__*/ import_react.createElement("spotLight", _extends$1({
		ref: spotlight,
		angle,
		color,
		distance,
		castShadow: true
	}, props), volumetric && /*#__PURE__*/ import_react.createElement(VolumetricMesh, {
		debug,
		opacity,
		radiusTop,
		radiusBottom,
		depthBuffer,
		color,
		distance,
		angle,
		attenuation,
		anglePower
	})), children && /*#__PURE__*/ import_react.cloneElement(children, {
		spotlightRef: spotlight,
		debug
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/Lightformer.js
var Lightformer = /* @__PURE__ */ import_react.forwardRef(({ light, args, map, toneMapped = false, color = "white", form: Form = "rect", intensity = 1, scale = 1, target = [
	0,
	0,
	0
], children, ...props }, forwardRef) => {
	const ref = import_react.useRef(null);
	import_react.useImperativeHandle(forwardRef, () => ref.current, []);
	import_react.useLayoutEffect(() => {
		if (!children && !props.material) {
			applyProps(ref.current.material, { color });
			ref.current.material.color.multiplyScalar(intensity);
		}
	}, [
		color,
		intensity,
		children,
		props.material
	]);
	import_react.useLayoutEffect(() => {
		if (!props.rotation) ref.current.quaternion.identity();
		if (target && !props.rotation) "boolean" === typeof target ? ref.current.lookAt(0, 0, 0) : ref.current.lookAt(Array.isArray(target) ? new Vector3(...target) : target);
	}, [target, props.rotation]);
	scale = Array.isArray(scale) && scale.length === 2 ? [
		scale[0],
		scale[1],
		1
	] : scale;
	return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({
		ref,
		scale
	}, props), Form === "circle" ? /*#__PURE__*/ import_react.createElement("ringGeometry", { args: args ? args : [
		0,
		.5,
		64
	] }) : Form === "ring" ? /*#__PURE__*/ import_react.createElement("ringGeometry", { args: args ? args : [
		.25,
		.5,
		64
	] }) : Form === "rect" || Form === "plane" ? /*#__PURE__*/ import_react.createElement("planeGeometry", { args: args ? args : [1, 1] }) : Form === "box" ? /*#__PURE__*/ import_react.createElement("boxGeometry", { args: args ? args : [
		1,
		1,
		1
	] }) : /*#__PURE__*/ import_react.createElement(Form, { args }), children ? children : /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		toneMapped,
		map,
		side: 2
	}), light && /*#__PURE__*/ import_react.createElement("pointLight", _extends$1({ castShadow: true }, light)));
});
//#endregion
//#region node_modules/@react-three/drei/core/Sky.js
function calcPosFromAngles(inclination, azimuth, vector = new Vector3()) {
	const theta = Math.PI * (inclination - .5);
	const phi = 2 * Math.PI * (azimuth - .5);
	vector.x = Math.cos(phi);
	vector.y = Math.sin(theta);
	vector.z = Math.sin(phi);
	return vector;
}
var Sky = /* @__PURE__ */ import_react.forwardRef(({ inclination = .6, azimuth = .1, distance = 1e3, mieCoefficient = .005, mieDirectionalG = .8, rayleigh = .5, turbidity = 10, sunPosition = calcPosFromAngles(inclination, azimuth), ...props }, ref) => {
	const scale = import_react.useMemo(() => new Vector3().setScalar(distance), [distance]);
	const [sky] = import_react.useState(() => new Sky$1());
	return /*#__PURE__*/ import_react.createElement("primitive", _extends$1({
		object: sky,
		ref,
		"material-uniforms-mieCoefficient-value": mieCoefficient,
		"material-uniforms-mieDirectionalG-value": mieDirectionalG,
		"material-uniforms-rayleigh-value": rayleigh,
		"material-uniforms-sunPosition-value": sunPosition,
		"material-uniforms-turbidity-value": turbidity,
		scale
	}, props));
});
//#endregion
//#region node_modules/@react-three/drei/core/Stars.js
var StarfieldMaterial = class extends ShaderMaterial {
	constructor() {
		super({
			uniforms: {
				time: { value: 0 },
				fade: { value: 1 }
			},
			vertexShader: `
      uniform float time;
      attribute float size;
      varying vec3 vColor;
      void main() {
        vColor = color;
        vec4 mvPosition = modelViewMatrix * vec4(position, 0.5);
        gl_PointSize = size * (30.0 / -mvPosition.z) * (3.0 + sin(time + 100.0));
        gl_Position = projectionMatrix * mvPosition;
      }`,
			fragmentShader: `
      uniform sampler2D pointTexture;
      uniform float fade;
      varying vec3 vColor;
      void main() {
        float opacity = 1.0;
        if (fade == 1.0) {
          float d = distance(gl_PointCoord, vec2(0.5, 0.5));
          opacity = 1.0 / (1.0 + exp(16.0 * (d - 0.25)));
        }
        gl_FragColor = vec4(vColor, opacity);

        #include 
	      #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
      }`
		});
	}
};
var genStar = (r) => {
	return new Vector3().setFromSpherical(new Spherical(r, Math.acos(1 - Math.random() * 2), Math.random() * 2 * Math.PI));
};
var Stars = /* @__PURE__ */ import_react.forwardRef(({ radius = 100, depth = 50, count = 5e3, saturation = 0, factor = 4, fade = false, speed = 1 }, ref) => {
	const material = import_react.useRef(null);
	const [position, color, size] = import_react.useMemo(() => {
		const positions = [];
		const colors = [];
		const sizes = Array.from({ length: count }, () => (.5 + .5 * Math.random()) * factor);
		const color = new Color();
		let r = radius + depth;
		const increment = depth / count;
		for (let i = 0; i < count; i++) {
			r -= increment * Math.random();
			positions.push(...genStar(r).toArray());
			color.setHSL(i / count, saturation, .9);
			colors.push(color.r, color.g, color.b);
		}
		return [
			new Float32Array(positions),
			new Float32Array(colors),
			new Float32Array(sizes)
		];
	}, [
		count,
		depth,
		factor,
		radius,
		saturation
	]);
	useFrame((state) => material.current && (material.current.uniforms.time.value = state.clock.elapsedTime * speed));
	const [starfieldMaterial] = import_react.useState(() => new StarfieldMaterial());
	return /*#__PURE__*/ import_react.createElement("points", { ref }, /*#__PURE__*/ import_react.createElement("bufferGeometry", null, /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-position",
		args: [position, 3]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-color",
		args: [color, 3]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-size",
		args: [size, 1]
	})), /*#__PURE__*/ import_react.createElement("primitive", {
		ref: material,
		object: starfieldMaterial,
		attach: "material",
		blending: 2,
		"uniforms-fade-value": fade,
		depthWrite: false,
		transparent: true,
		vertexColors: true
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/Cloud.js
var CLOUD_URL = "https://rawcdn.githack.com/pmndrs/drei-assets/9225a9f1fbd449d9411125c2f419b843d0308c9f/cloud.png";
var parentMatrix$1 = /* @__PURE__ */ new Matrix4();
var translation = /* @__PURE__ */ new Vector3();
var rotation = /* @__PURE__ */ new Quaternion();
var cpos = /* @__PURE__ */ new Vector3();
var cquat = /* @__PURE__ */ new Quaternion();
var scale = /* @__PURE__ */ new Vector3();
var context$4 = /* @__PURE__ */ import_react.createContext(null);
var Clouds = /* @__PURE__ */ import_react.forwardRef(({ children, material = MeshLambertMaterial, texture = CLOUD_URL, range, limit = 200, frustumCulled, ...props }, fref) => {
	var _image$width, _image$height;
	extend({ CloudMaterial: import_react.useMemo(() => {
		return class extends material {
			constructor() {
				super();
				const opaque_fragment = parseInt("184".replace(/\D+/g, "")) >= 154 ? "opaque_fragment" : "output_fragment";
				this.onBeforeCompile = (shader) => {
					shader.vertexShader = `attribute float cloudOpacity;
               varying float vOpacity;
              ` + shader.vertexShader.replace("#include ", `#include 
                 vOpacity = cloudOpacity;
                `);
					shader.fragmentShader = `varying float vOpacity;
              ` + shader.fragmentShader.replace(`#include <${opaque_fragment}>`, `#include <${opaque_fragment}>
                 gl_FragColor = vec4(outgoingLight, diffuseColor.a * vOpacity);
                `);
				};
			}
		};
	}, [material]) });
	const instance = import_react.useRef(null);
	const clouds = import_react.useRef([]);
	const opacities = import_react.useMemo(() => new Float32Array(Array.from({ length: limit }, () => 1)), [limit]);
	const colors = import_react.useMemo(() => new Float32Array(Array.from({ length: limit }, () => [
		1,
		1,
		1
	]).flat()), [limit]);
	const cloudTexture = useTexture(texture);
	let t = 0;
	let index = 0;
	let config;
	const qat = new Quaternion();
	const dir = new Vector3(0, 0, 1);
	const pos = new Vector3();
	useFrame((state, delta) => {
		t = state.clock.elapsedTime;
		parentMatrix$1.copy(instance.current.matrixWorld).invert();
		state.camera.matrixWorld.decompose(cpos, cquat, scale);
		for (index = 0; index < clouds.current.length; index++) {
			config = clouds.current[index];
			config.ref.current.matrixWorld.decompose(translation, rotation, scale);
			translation.add(pos.copy(config.position).applyQuaternion(rotation).multiply(scale));
			rotation.copy(cquat).multiply(qat.setFromAxisAngle(dir, config.rotation += delta * config.rotationFactor));
			scale.multiplyScalar(config.volume + (1 + Math.sin(t * config.density * config.speed)) / 2 * config.growth);
			config.matrix.compose(translation, rotation, scale).premultiply(parentMatrix$1);
			config.dist = translation.distanceTo(cpos);
		}
		clouds.current.sort((a, b) => b.dist - a.dist);
		for (index = 0; index < clouds.current.length; index++) {
			config = clouds.current[index];
			opacities[index] = config.opacity * (config.dist < config.fade - 1 ? config.dist / config.fade : 1);
			instance.current.setMatrixAt(index, config.matrix);
			instance.current.setColorAt(index, config.color);
		}
		instance.current.geometry.attributes.cloudOpacity.needsUpdate = true;
		instance.current.instanceMatrix.needsUpdate = true;
		if (instance.current.instanceColor) instance.current.instanceColor.needsUpdate = true;
	});
	import_react.useLayoutEffect(() => {
		const count = Math.min(limit, range !== void 0 ? range : limit, clouds.current.length);
		instance.current.count = count;
		setUpdateRange(instance.current.instanceMatrix, {
			start: 0,
			count: count * 16
		});
		if (instance.current.instanceColor) setUpdateRange(instance.current.instanceColor, {
			start: 0,
			count: count * 3
		});
		setUpdateRange(instance.current.geometry.attributes.cloudOpacity, {
			start: 0,
			count
		});
	});
	let imageBounds = [(_image$width = cloudTexture.image.width) !== null && _image$width !== void 0 ? _image$width : 1, (_image$height = cloudTexture.image.height) !== null && _image$height !== void 0 ? _image$height : 1];
	const max = Math.max(imageBounds[0], imageBounds[1]);
	imageBounds = [imageBounds[0] / max, imageBounds[1] / max];
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: fref }, props), /*#__PURE__*/ import_react.createElement(context$4.Provider, { value: clouds }, children, /*#__PURE__*/ import_react.createElement("instancedMesh", {
		matrixAutoUpdate: false,
		ref: instance,
		args: [
			null,
			null,
			limit
		],
		frustumCulled
	}, /*#__PURE__*/ import_react.createElement("instancedBufferAttribute", {
		usage: DynamicDrawUsage,
		attach: "instanceColor",
		args: [colors, 3]
	}), /*#__PURE__*/ import_react.createElement("planeGeometry", { args: [...imageBounds] }, /*#__PURE__*/ import_react.createElement("instancedBufferAttribute", {
		usage: DynamicDrawUsage,
		attach: "attributes-cloudOpacity",
		args: [opacities, 1]
	})), /*#__PURE__*/ import_react.createElement("cloudMaterial", {
		key: material.name,
		map: cloudTexture,
		transparent: true,
		depthWrite: false
	}))));
});
var CloudInstance = /* @__PURE__ */ import_react.forwardRef(({ opacity = 1, speed = 0, bounds = [
	5,
	1,
	1
], segments = 20, color = "#ffffff", fade = 10, volume = 6, smallestVolume = .25, distribute = null, growth = 4, concentrate = "inside", seed = Math.random(), ...props }, fref) => {
	function random() {
		const x = Math.sin(seed++) * 1e4;
		return x - Math.floor(x);
	}
	const parent = import_react.useContext(context$4);
	const ref = import_react.useRef(null);
	const uuid = import_react.useId();
	const clouds = import_react.useMemo(() => {
		return [...new Array(segments)].map((_, index) => ({
			segments,
			bounds: new Vector3(1, 1, 1),
			position: new Vector3(),
			uuid,
			index,
			ref,
			dist: 0,
			matrix: new Matrix4(),
			color: new Color(),
			rotation: index * (Math.PI / segments)
		}));
	}, [segments, uuid]);
	import_react.useLayoutEffect(() => {
		clouds.forEach((cloud, index) => {
			applyProps(cloud, {
				volume,
				color,
				speed,
				growth,
				opacity,
				fade,
				bounds,
				density: Math.max(.5, random()),
				rotationFactor: Math.max(.2, .5 * random()) * speed
			});
			const distributed = distribute == null ? void 0 : distribute(cloud, index);
			if (distributed || segments > 1) {
				var _distributed$point;
				cloud.position.copy(cloud.bounds).multiply((_distributed$point = distributed == null ? void 0 : distributed.point) !== null && _distributed$point !== void 0 ? _distributed$point : {
					x: random() * 2 - 1,
					y: random() * 2 - 1,
					z: random() * 2 - 1
				});
			}
			const xDiff = Math.abs(cloud.position.x);
			const yDiff = Math.abs(cloud.position.y);
			const zDiff = Math.abs(cloud.position.z);
			const max = Math.max(xDiff, yDiff, zDiff);
			cloud.length = 1;
			if (xDiff === max) cloud.length -= xDiff / cloud.bounds.x;
			if (yDiff === max) cloud.length -= yDiff / cloud.bounds.y;
			if (zDiff === max) cloud.length -= zDiff / cloud.bounds.z;
			cloud.volume = ((distributed == null ? void 0 : distributed.volume) !== void 0 ? distributed.volume : Math.max(Math.max(0, smallestVolume), concentrate === "random" ? random() : concentrate === "inside" ? cloud.length : 1 - cloud.length)) * volume;
		});
	}, [
		concentrate,
		bounds,
		fade,
		color,
		opacity,
		growth,
		volume,
		seed,
		segments,
		speed
	]);
	import_react.useLayoutEffect(() => {
		const temp = clouds;
		parent.current = [...parent.current, ...temp];
		return () => {
			parent.current = parent.current.filter((item) => item.uuid !== uuid);
		};
	}, [clouds]);
	import_react.useImperativeHandle(fref, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref }, props));
});
var Cloud = /* @__PURE__ */ import_react.forwardRef((props, fref) => {
	if (import_react.useContext(context$4)) return /*#__PURE__*/ import_react.createElement(CloudInstance, _extends$1({ ref: fref }, props));
	return /*#__PURE__*/ import_react.createElement(Clouds, null, /*#__PURE__*/ import_react.createElement(CloudInstance, _extends$1({ ref: fref }, props)));
});
//#endregion
//#region node_modules/@react-three/drei/core/Sparkles.js
var SparklesImplMaterial = class extends ShaderMaterial {
	constructor() {
		super({
			uniforms: {
				time: { value: 0 },
				pixelRatio: { value: 1 }
			},
			vertexShader: `
        uniform float pixelRatio;
        uniform float time;
        attribute float size;  
        attribute float speed;  
        attribute float opacity;
        attribute vec3 noise;
        attribute vec3 color;
        varying vec3 vColor;
        varying float vOpacity;

        void main() {
          vec4 modelPosition = modelMatrix * vec4(position, 1.0);
          modelPosition.y += sin(time * speed + modelPosition.x * noise.x * 100.0) * 0.2;
          modelPosition.z += cos(time * speed + modelPosition.x * noise.y * 100.0) * 0.2;
          modelPosition.x += cos(time * speed + modelPosition.x * noise.z * 100.0) * 0.2;
          vec4 viewPosition = viewMatrix * modelPosition;
          vec4 projectionPostion = projectionMatrix * viewPosition;
          gl_Position = projectionPostion;
          gl_PointSize = size * 25. * pixelRatio;
          gl_PointSize *= (1.0 / - viewPosition.z);
          vColor = color;
          vOpacity = opacity;
        }
      `,
			fragmentShader: `
        varying vec3 vColor;
        varying float vOpacity;
        void main() {
          float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
          float strength = 0.05 / distanceToCenter - 0.1;
          gl_FragColor = vec4(vColor, strength * vOpacity);
          #include 
          #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
        }
      `
		});
	}
	get time() {
		return this.uniforms.time.value;
	}
	set time(value) {
		this.uniforms.time.value = value;
	}
	get pixelRatio() {
		return this.uniforms.pixelRatio.value;
	}
	set pixelRatio(value) {
		this.uniforms.pixelRatio.value = value;
	}
};
var isFloat32Array = (def) => def && def.constructor === Float32Array;
var expandColor = (v) => [
	v.r,
	v.g,
	v.b
];
var isVector = (v) => v instanceof Vector2 || v instanceof Vector3 || v instanceof Vector4;
var normalizeVector = (v) => {
	if (Array.isArray(v)) return v;
	else if (isVector(v)) return v.toArray();
	return [
		v,
		v,
		v
	];
};
function usePropAsIsOrAsAttribute(count, prop, setDefault) {
	return import_react.useMemo(() => {
		if (prop !== void 0) if (isFloat32Array(prop)) return prop;
		else {
			if (prop instanceof Color) {
				const a = Array.from({ length: count * 3 }, () => expandColor(prop)).flat();
				return Float32Array.from(a);
			} else if (isVector(prop) || Array.isArray(prop)) {
				const a = Array.from({ length: count * 3 }, () => normalizeVector(prop)).flat();
				return Float32Array.from(a);
			}
			return Float32Array.from({ length: count }, () => prop);
		}
		return Float32Array.from({ length: count }, setDefault);
	}, [prop]);
}
var Sparkles = /* @__PURE__ */ import_react.forwardRef(({ noise = 1, count = 100, speed = 1, opacity = 1, scale = 1, size, color, children, ...props }, forwardRef) => {
	import_react.useMemo(() => extend({ SparklesImplMaterial }), []);
	const ref = import_react.useRef(null);
	const dpr = useThree((state) => state.viewport.dpr);
	const _scale = normalizeVector(scale);
	const positions = import_react.useMemo(() => Float32Array.from(Array.from({ length: count }, () => _scale.map(MathUtils.randFloatSpread)).flat()), [count, ..._scale]);
	const sizes = usePropAsIsOrAsAttribute(count, size, Math.random);
	const opacities = usePropAsIsOrAsAttribute(count, opacity);
	const speeds = usePropAsIsOrAsAttribute(count, speed);
	const noises = usePropAsIsOrAsAttribute(count * 3, noise);
	const colors = usePropAsIsOrAsAttribute(color === void 0 ? count * 3 : count, !isFloat32Array(color) ? new Color(color) : color, () => 1);
	useFrame((state) => {
		if (ref.current && ref.current.material) ref.current.material.time = state.clock.elapsedTime;
	});
	import_react.useImperativeHandle(forwardRef, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("points", _extends$1({ key: `particle-${count}-${JSON.stringify(scale)}` }, props, { ref }), /*#__PURE__*/ import_react.createElement("bufferGeometry", null, /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-position",
		args: [positions, 3]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-size",
		args: [sizes, 1]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-opacity",
		args: [opacities, 1]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-speed",
		args: [speeds, 1]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-color",
		args: [colors, 3]
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-noise",
		args: [noises, 3]
	})), children ? children : /*#__PURE__*/ import_react.createElement("sparklesImplMaterial", {
		transparent: true,
		pixelRatio: dpr,
		depthWrite: false
	}));
});
//#endregion
//#region node_modules/@react-three/drei/core/MatcapTexture.js
function getFormatString(format) {
	switch (format) {
		case 64: return "-64px";
		case 128: return "-128px";
		case 256: return "-256px";
		case 512: return "-512px";
		default: return "";
	}
}
var LIST_URL$1 = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/matcaps.json";
var MATCAP_ROOT = "https://rawcdn.githack.com/emmelleppi/matcaps/9b36ccaaf0a24881a39062d05566c9e92be4aa0d";
function useMatcapTexture(id = 0, format = 1024, onLoad) {
	const matcapList = suspend(() => fetch(LIST_URL$1).then((res) => res.json()), ["matcapList"]);
	const DEFAULT_MATCAP = matcapList[0];
	const numTot = import_react.useMemo(() => Object.keys(matcapList).length, []);
	const url = `${MATCAP_ROOT}/${format}/${`${import_react.useMemo(() => {
		if (typeof id === "string") return id;
		else if (typeof id === "number") return matcapList[id];
		return null;
	}, [id]) || DEFAULT_MATCAP}${getFormatString(format)}.png`}`;
	return [
		useTexture(url, onLoad),
		url,
		numTot
	];
}
var MatcapTexture = ({ children, id, format, onLoad }) => {
	const texture = useMatcapTexture(id, format, onLoad);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(texture));
};
//#endregion
//#region node_modules/@react-three/drei/core/NormalTexture.js
var NORMAL_ROOT = "https://rawcdn.githack.com/pmndrs/drei-assets/7a3104997e1576f83472829815b00880d88b32fb";
var LIST_URL = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/normals/normals.json";
function useNormalTexture(id = 0, settings = {}, onLoad) {
	const { repeat = [1, 1], anisotropy = 1, offset = [0, 0] } = settings;
	const normalsList = suspend(() => fetch(LIST_URL).then((res) => res.json()), ["normalsList"]);
	const numTot = import_react.useMemo(() => Object.keys(normalsList).length, []);
	const DEFAULT_NORMAL = normalsList[0];
	const url = `${NORMAL_ROOT}/normals/${normalsList[id] || DEFAULT_NORMAL}`;
	const normalTexture = useTexture(url, onLoad);
	import_react.useLayoutEffect(() => {
		if (!normalTexture) return;
		normalTexture.wrapS = normalTexture.wrapT = RepeatWrapping;
		normalTexture.repeat = new Vector2(repeat[0], repeat[1]);
		normalTexture.offset = new Vector2(offset[0], offset[1]);
		normalTexture.anisotropy = anisotropy;
	}, [
		normalTexture,
		anisotropy,
		repeat,
		offset
	]);
	return [
		normalTexture,
		url,
		numTot
	];
}
var NormalTexture = ({ children, id, onLoad, ...settings }) => {
	const ret = useNormalTexture(id, settings, onLoad);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children == null ? void 0 : children(ret));
};
//#endregion
//#region node_modules/@react-three/drei/materials/WireframeMaterial.js
var WireframeMaterialShaders = {
	uniforms: {
		strokeOpacity: 1,
		fillOpacity: .25,
		fillMix: 0,
		thickness: .05,
		colorBackfaces: false,
		dashInvert: true,
		dash: false,
		dashRepeats: 4,
		dashLength: .5,
		squeeze: false,
		squeezeMin: .2,
		squeezeMax: 1,
		stroke: /* @__PURE__ */ new Color("#ff0000"),
		backfaceStroke: /* @__PURE__ */ new Color("#0000ff"),
		fill: /* @__PURE__ */ new Color("#00ff00")
	},
	vertex: `
	  attribute vec3 barycentric;
	
		varying vec3 v_edges_Barycentric;
		varying vec3 v_edges_Position;

		void initWireframe() {
			v_edges_Barycentric = barycentric;
			v_edges_Position = position.xyz;
		}
	  `,
	fragment: `
		#ifndef PI
	  	#define PI 3.1415926535897932384626433832795
		#endif
  
	  varying vec3 v_edges_Barycentric;
	  varying vec3 v_edges_Position;
  
	  uniform float strokeOpacity;
	  uniform float fillOpacity;
	  uniform float fillMix;
	  uniform float thickness;
	  uniform bool colorBackfaces;
  
	  // Dash
	  uniform bool dashInvert;
	  uniform bool dash;
	  uniform bool dashOnly;
	  uniform float dashRepeats;
	  uniform float dashLength;
  
	  // Squeeze
	  uniform bool squeeze;
	  uniform float squeezeMin;
	  uniform float squeezeMax;
  
	  // Colors
	  uniform vec3 stroke;
	  uniform vec3 backfaceStroke;
	  uniform vec3 fill;
  
	  // This is like
	  float wireframe_aastep(float threshold, float dist) {
		  float afwidth = fwidth(dist) * 0.5;
		  return smoothstep(threshold - afwidth, threshold + afwidth, dist);
	  }
  
	  float wireframe_map(float value, float min1, float max1, float min2, float max2) {
		  return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
	  }
  
	  float getWireframe() {
			vec3 barycentric = v_edges_Barycentric;
		
			// Distance from center of each triangle to its edges.
			float d = min(min(barycentric.x, barycentric.y), barycentric.z);

			// for dashed rendering, we can use this to get the 0 .. 1 value of the line length
			float positionAlong = max(barycentric.x, barycentric.y);
			if (barycentric.y < barycentric.x && barycentric.y < barycentric.z) {
				positionAlong = 1.0 - positionAlong;
			}

			// the thickness of the stroke
			float computedThickness = wireframe_map(thickness, 0.0, 1.0, 0.0, 0.34);

			// if we want to shrink the thickness toward the center of the line segment
			if (squeeze) {
				computedThickness *= mix(squeezeMin, squeezeMax, (1.0 - sin(positionAlong * PI)));
			}

			// Create dash pattern
			if (dash) {
				// here we offset the stroke position depending on whether it
				// should overlap or not
				float offset = 1.0 / dashRepeats * dashLength / 2.0;
				if (!dashInvert) {
					offset += 1.0 / dashRepeats / 2.0;
				}

				// if we should animate the dash or not
				// if (dashAnimate) {
				// 	offset += time * 0.22;
				// }

				// create the repeating dash pattern
				float pattern = fract((positionAlong + offset) * dashRepeats);
				computedThickness *= 1.0 - wireframe_aastep(dashLength, pattern);
			}

			// compute the anti-aliased stroke edge  
			float edge = 1.0 - wireframe_aastep(computedThickness, d);

			return edge;
	  }
	  `
};
var WireframeMaterial = /* @__PURE__ */ shaderMaterial(WireframeMaterialShaders.uniforms, WireframeMaterialShaders.vertex + `
  	void main() {
		initWireframe();
		gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
	}
  `, WireframeMaterialShaders.fragment + `
  void main () {
		// Compute color

		float edge = getWireframe();
		vec4 colorStroke = vec4(stroke, edge);

		#ifdef FLIP_SIDED
			colorStroke.rgb = backfaceStroke;
		#endif
    
		vec4 colorFill = vec4(fill, fillOpacity);
		vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);

		gl_FragColor = outColor;
	}
  `);
function setWireframeOverride(material, uniforms) {
	material.onBeforeCompile = (shader) => {
		shader.uniforms = {
			...shader.uniforms,
			...uniforms
		};
		shader.vertexShader = shader.vertexShader.replace("void main() {", `
		  ${WireframeMaterialShaders.vertex}
		  void main() {
			initWireframe();
		`);
		shader.fragmentShader = shader.fragmentShader.replace("void main() {", `
		  ${WireframeMaterialShaders.fragment}
		  void main() {
		`);
		shader.fragmentShader = shader.fragmentShader.replace("#include ", `
		  #include 
			  float edge = getWireframe();
		  vec4 colorStroke = vec4(stroke, edge);
		  #ifdef FLIP_SIDED
			colorStroke.rgb = backfaceStroke;
		  #endif
		  vec4 colorFill = vec4(mix(diffuseColor.rgb, fill, fillMix), mix(diffuseColor.a, fillOpacity, fillMix));
		  vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);

		  diffuseColor.rgb = outColor.rgb;
		  diffuseColor.a *= outColor.a;
		`);
	};
	material.side = 2;
	material.transparent = true;
}
function useWireframeUniforms(uniforms, props) {
	import_react.useEffect(() => {
		var _props$fillOpacity;
		uniforms.fillOpacity.value = (_props$fillOpacity = props.fillOpacity) !== null && _props$fillOpacity !== void 0 ? _props$fillOpacity : uniforms.fillOpacity.value;
	}, [props.fillOpacity]);
	import_react.useEffect(() => {
		var _props$fillMix;
		uniforms.fillMix.value = (_props$fillMix = props.fillMix) !== null && _props$fillMix !== void 0 ? _props$fillMix : uniforms.fillMix.value;
	}, [props.fillMix]);
	import_react.useEffect(() => {
		var _props$strokeOpacity;
		uniforms.strokeOpacity.value = (_props$strokeOpacity = props.strokeOpacity) !== null && _props$strokeOpacity !== void 0 ? _props$strokeOpacity : uniforms.strokeOpacity.value;
	}, [props.strokeOpacity]);
	import_react.useEffect(() => {
		var _props$thickness;
		uniforms.thickness.value = (_props$thickness = props.thickness) !== null && _props$thickness !== void 0 ? _props$thickness : uniforms.thickness.value;
	}, [props.thickness]);
	import_react.useEffect(() => void (uniforms.colorBackfaces.value = !!props.colorBackfaces), [props.colorBackfaces]);
	import_react.useEffect(() => void (uniforms.dash.value = !!props.dash), [props.dash]);
	import_react.useEffect(() => void (uniforms.dashInvert.value = !!props.dashInvert), [props.dashInvert]);
	import_react.useEffect(() => {
		var _props$dashRepeats;
		uniforms.dashRepeats.value = (_props$dashRepeats = props.dashRepeats) !== null && _props$dashRepeats !== void 0 ? _props$dashRepeats : uniforms.dashRepeats.value;
	}, [props.dashRepeats]);
	import_react.useEffect(() => {
		var _props$dashLength;
		uniforms.dashLength.value = (_props$dashLength = props.dashLength) !== null && _props$dashLength !== void 0 ? _props$dashLength : uniforms.dashLength.value;
	}, [props.dashLength]);
	import_react.useEffect(() => void (uniforms.squeeze.value = !!props.squeeze), [props.squeeze]);
	import_react.useEffect(() => {
		var _props$squeezeMin;
		uniforms.squeezeMin.value = (_props$squeezeMin = props.squeezeMin) !== null && _props$squeezeMin !== void 0 ? _props$squeezeMin : uniforms.squeezeMin.value;
	}, [props.squeezeMin]);
	import_react.useEffect(() => {
		var _props$squeezeMax;
		uniforms.squeezeMax.value = (_props$squeezeMax = props.squeezeMax) !== null && _props$squeezeMax !== void 0 ? _props$squeezeMax : uniforms.squeezeMax.value;
	}, [props.squeezeMax]);
	import_react.useEffect(() => void (uniforms.stroke.value = props.stroke ? new Color(props.stroke) : uniforms.stroke.value), [props.stroke]);
	import_react.useEffect(() => void (uniforms.fill.value = props.fill ? new Color(props.fill) : uniforms.fill.value), [props.fill]);
	import_react.useEffect(() => void (uniforms.backfaceStroke.value = props.backfaceStroke ? new Color(props.backfaceStroke) : uniforms.backfaceStroke.value), [props.backfaceStroke]);
}
//#endregion
//#region node_modules/@react-three/drei/core/Wireframe.js
function isWithGeometry(object) {
	return !!(object != null && object.geometry);
}
function isGeometry(object) {
	return !!(object != null && object.isBufferGeometry);
}
function isRefObject(object) {
	return !!(object != null && object.current);
}
function isRef(object) {
	return (object == null ? void 0 : object.current) !== void 0;
}
function isWireframeGeometry(geometry) {
	return geometry.type === "WireframeGeometry";
}
function getUniforms() {
	const u = {};
	for (const key in WireframeMaterialShaders.uniforms) u[key] = { value: WireframeMaterialShaders.uniforms[key] };
	return u;
}
function getBarycentricCoordinates(geometry, removeEdge) {
	const count = geometry.getAttribute("position").count;
	const barycentric = [];
	for (let i = 0; i < count; i++) {
		const even = i % 2 === 0;
		const Q = removeEdge ? 1 : 0;
		if (even) barycentric.push(0, 0, 1, 0, 1, 0, 1, 0, Q);
		else barycentric.push(0, 1, 0, 0, 0, 1, 1, 0, Q);
	}
	return new BufferAttribute(Float32Array.from(barycentric), 3);
}
function getInputGeometry(inputGeometry) {
	const geo = isRefObject(inputGeometry) ? inputGeometry.current : inputGeometry;
	if (!isGeometry(geo)) {
		if (isWireframeGeometry(geo)) throw new Error("Wireframe: WireframeGeometry is not supported.");
		const parent = geo.parent;
		if (isWithGeometry(parent)) {
			if (isWireframeGeometry(parent.geometry)) throw new Error("Wireframe: WireframeGeometry is not supported.");
			return parent.geometry;
		}
	} else return geo;
}
function setBarycentricCoordinates(geometry, simplify) {
	if (geometry.index) {
		console.warn("Wireframe: Requires non-indexed geometry, converting to non-indexed geometry.");
		const nonIndexedGeo = geometry.toNonIndexed();
		geometry.copy(nonIndexedGeo);
		geometry.setIndex(null);
	}
	const newBarycentric = getBarycentricCoordinates(geometry, simplify);
	geometry.setAttribute("barycentric", newBarycentric);
}
function WireframeWithCustomGeo({ geometry: customGeometry, simplify = false, ...props }) {
	extend({ MeshWireframeMaterial: WireframeMaterial });
	const [geometry, setGeometry] = import_react.useState(null);
	import_react.useLayoutEffect(() => {
		const geom = getInputGeometry(customGeometry);
		if (!geom) throw new Error("Wireframe: geometry prop must be a BufferGeometry or a ref to a BufferGeometry.");
		setBarycentricCoordinates(geom, simplify);
		if (isRef(customGeometry)) setGeometry(geom);
	}, [simplify, customGeometry]);
	const drawnGeo = isRef(customGeometry) ? geometry : customGeometry;
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, drawnGeo && /*#__PURE__*/ import_react.createElement("mesh", { geometry: drawnGeo }, /*#__PURE__*/ import_react.createElement("meshWireframeMaterial", _extends$1({
		attach: "material",
		transparent: true,
		side: 2,
		polygonOffset: true,
		polygonOffsetFactor: -4
	}, props, { extensions: {
		derivatives: true,
		fragDepth: false,
		drawBuffers: false,
		shaderTextureLOD: false
	} }))));
}
function WireframeWithoutCustomGeo({ simplify = false, ...props }) {
	const objectRef = import_react.useRef(null);
	const uniforms = import_react.useMemo(() => getUniforms(), [WireframeMaterialShaders.uniforms]);
	useWireframeUniforms(uniforms, props);
	import_react.useLayoutEffect(() => {
		const geom = getInputGeometry(objectRef);
		if (!geom) throw new Error("Wireframe: Must be a child of a Mesh, Line or Points object or specify a geometry prop.");
		const og = geom.clone();
		setBarycentricCoordinates(geom, simplify);
		return () => {
			geom.copy(og);
			og.dispose();
		};
	}, [simplify]);
	import_react.useLayoutEffect(() => {
		const parentMesh = objectRef.current.parent;
		const og = parentMesh.material.clone();
		setWireframeOverride(parentMesh.material, uniforms);
		return () => {
			parentMesh.material.dispose();
			parentMesh.material = og;
		};
	}, []);
	return /*#__PURE__*/ import_react.createElement("object3D", { ref: objectRef });
}
function Wireframe({ geometry: customGeometry, ...props }) {
	if (customGeometry) return /*#__PURE__*/ import_react.createElement(WireframeWithCustomGeo, _extends$1({ geometry: customGeometry }, props));
	return /*#__PURE__*/ import_react.createElement(WireframeWithoutCustomGeo, props);
}
//#endregion
//#region node_modules/@react-three/drei/core/ShadowAlpha.js
/**
* Integration and compilation: Faraz Shaikh (https://twitter.com/CantBeFaraz)
*
* Based on:
*  - https://gkjohnson.github.io/threejs-sandbox/screendoor-transparency/ by Garrett Johnson (https://github.com/gkjohnson)
*
* Note:
*  - Must depreciate in favor of https://github.com/mrdoob/three.js/issues/10600 when it's ready.
*/
function ShadowAlpha({ opacity, alphaMap }) {
	const depthMaterialRef = import_react.useRef(null);
	const distanceMaterialRef = import_react.useRef(null);
	const uShadowOpacity = import_react.useRef({ value: 1 });
	const uAlphaMap = import_react.useRef({ value: null });
	const uHasAlphaMap = import_react.useRef({ value: false });
	import_react.useLayoutEffect(() => {
		depthMaterialRef.current.onBeforeCompile = distanceMaterialRef.current.onBeforeCompile = (shader) => {
			const mainLineStart = shader.fragmentShader.indexOf("void main");
			let mainLine = "";
			let ch;
			let i = mainLineStart;
			while (ch !== "\n" && i < mainLineStart + 100) {
				ch = shader.fragmentShader.charAt(i);
				mainLine += ch;
				i++;
			}
			mainLine = mainLine.trim();
			shader.vertexShader = shader.vertexShader.replace("void main() {", `
        varying vec2 custom_vUv;

        void main() {
          custom_vUv = uv;
          
        `);
			shader.fragmentShader = shader.fragmentShader.replace(mainLine, `
          uniform float uShadowOpacity;
          uniform sampler2D uAlphaMap;
          uniform bool uHasAlphaMap;

          varying vec2 custom_vUv;
  
          float bayerDither2x2( vec2 v ) {
            return mod( 3.0 * v.y + 2.0 * v.x, 4.0 );
          }
    
          float bayerDither4x4( vec2 v ) {
            vec2 P1 = mod( v, 2.0 );
            vec2 P2 = mod( floor( 0.5  * v ), 2.0 );
            return 4.0 * bayerDither2x2( P1 ) + bayerDither2x2( P2 );
          }
  
          void main() {
            float alpha = 
              uHasAlphaMap ? 
                uShadowOpacity * texture2D(uAlphaMap, custom_vUv).x
              : uShadowOpacity;

            if( ( bayerDither4x4( floor( mod( gl_FragCoord.xy, 4.0 ) ) ) ) / 16.0 >= alpha ) discard;
            
          `);
			shader.uniforms["uShadowOpacity"] = uShadowOpacity.current;
			shader.uniforms["uAlphaMap"] = uAlphaMap.current;
			shader.uniforms["uHasAlphaMap"] = uHasAlphaMap.current;
		};
	}, []);
	useFrame(() => {
		var _r3f;
		const parent = (_r3f = depthMaterialRef.current.__r3f) == null || (_r3f = _r3f.parent) == null ? void 0 : _r3f.object;
		if (parent) {
			const parentMainMaterial = parent.material;
			if (parentMainMaterial) {
				uShadowOpacity.current.value = opacity !== null && opacity !== void 0 ? opacity : parentMainMaterial.opacity;
				if (alphaMap === false) {
					uAlphaMap.current.value = null;
					uHasAlphaMap.current.value = false;
				} else {
					uAlphaMap.current.value = alphaMap || parentMainMaterial.alphaMap;
					uHasAlphaMap.current.value = !!uAlphaMap.current.value;
				}
			}
		}
	});
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("meshDepthMaterial", {
		ref: depthMaterialRef,
		attach: "customDepthMaterial",
		depthPacking: RGBADepthPacking
	}), /*#__PURE__*/ import_react.createElement("meshDistanceMaterial", {
		ref: distanceMaterialRef,
		attach: "customDistanceMaterial"
	}));
}
//#endregion
//#region node_modules/@react-three/drei/core/Points.js
var _inverseMatrix$1 = /* @__PURE__ */ new Matrix4();
var _ray$1 = /* @__PURE__ */ new Ray();
var _sphere$1 = /* @__PURE__ */ new Sphere$1();
var _position = /* @__PURE__ */ new Vector3();
var PositionPoint = class extends Group {
	constructor() {
		super();
		this.size = 0;
		this.color = new Color("white");
		this.instance = { current: void 0 };
		this.instanceKey = { current: void 0 };
	}
	get geometry() {
		var _this$instance$curren;
		return (_this$instance$curren = this.instance.current) == null ? void 0 : _this$instance$curren.geometry;
	}
	raycast(raycaster, intersects) {
		var _raycaster$params$Poi, _raycaster$params$Poi2;
		const parent = this.instance.current;
		if (!parent || !parent.geometry) return;
		const instanceId = parent.userData.instances.indexOf(this.instanceKey);
		if (instanceId === -1 || instanceId > parent.geometry.drawRange.count) return;
		const threshold = (_raycaster$params$Poi = (_raycaster$params$Poi2 = raycaster.params.Points) == null ? void 0 : _raycaster$params$Poi2.threshold) !== null && _raycaster$params$Poi !== void 0 ? _raycaster$params$Poi : 1;
		_sphere$1.set(this.getWorldPosition(_position), threshold);
		if (raycaster.ray.intersectsSphere(_sphere$1) === false) return;
		_inverseMatrix$1.copy(parent.matrixWorld).invert();
		_ray$1.copy(raycaster.ray).applyMatrix4(_inverseMatrix$1);
		const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3);
		const localThresholdSq = localThreshold * localThreshold;
		const rayPointDistanceSq = _ray$1.distanceSqToPoint(this.position);
		if (rayPointDistanceSq < localThresholdSq) {
			const intersectPoint = new Vector3();
			_ray$1.closestPointToPoint(this.position, intersectPoint);
			intersectPoint.applyMatrix4(this.matrixWorld);
			const distance = raycaster.ray.origin.distanceTo(intersectPoint);
			if (distance < raycaster.near || distance > raycaster.far) return;
			intersects.push({
				distance,
				distanceToRay: Math.sqrt(rayPointDistanceSq),
				point: intersectPoint,
				index: instanceId,
				face: null,
				object: this
			});
		}
	}
};
var i, positionRef;
var context$3 = /* @__PURE__ */ import_react.createContext(null);
var parentMatrix = /* @__PURE__ */ new Matrix4();
var position = /* @__PURE__ */ new Vector3();
/**
* Instance implementation, relies on react + context to update the attributes based on the children of this component
*/
var PointsInstances = /* @__PURE__ */ import_react.forwardRef(({ children, range, limit = 1e3, ...props }, ref) => {
	const parentRef = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => parentRef.current, []);
	const [refs, setRefs] = import_react.useState([]);
	const [[positions, colors, sizes]] = import_react.useState(() => [
		new Float32Array(limit * 3),
		Float32Array.from({ length: limit * 3 }, () => 1),
		Float32Array.from({ length: limit }, () => 1)
	]);
	import_react.useEffect(() => {
		parentRef.current.geometry.attributes.position.needsUpdate = true;
	});
	useFrame(() => {
		parentRef.current.updateMatrix();
		parentRef.current.updateMatrixWorld();
		parentMatrix.copy(parentRef.current.matrixWorld).invert();
		parentRef.current.geometry.drawRange.count = Math.min(limit, range !== void 0 ? range : limit, refs.length);
		for (i = 0; i < refs.length; i++) {
			positionRef = refs[i].current;
			positionRef.getWorldPosition(position).applyMatrix4(parentMatrix);
			position.toArray(positions, i * 3);
			parentRef.current.geometry.attributes.position.needsUpdate = true;
			positionRef.matrixWorldNeedsUpdate = true;
			positionRef.color.toArray(colors, i * 3);
			parentRef.current.geometry.attributes.color.needsUpdate = true;
			sizes.set([positionRef.size], i);
			parentRef.current.geometry.attributes.size.needsUpdate = true;
		}
	});
	const api = import_react.useMemo(() => ({
		getParent: () => parentRef,
		subscribe: (ref) => {
			setRefs((refs) => [...refs, ref]);
			return () => setRefs((refs) => refs.filter((item) => item.current !== ref.current));
		}
	}), []);
	return /*#__PURE__*/ import_react.createElement("points", _extends$1({
		userData: { instances: refs },
		matrixAutoUpdate: false,
		ref: parentRef,
		raycast: () => null
	}, props), /*#__PURE__*/ import_react.createElement("bufferGeometry", null, /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-position",
		args: [positions, 3],
		usage: DynamicDrawUsage
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-color",
		args: [colors, 3],
		usage: DynamicDrawUsage
	}), /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-size",
		args: [sizes, 1],
		usage: DynamicDrawUsage
	})), /*#__PURE__*/ import_react.createElement(context$3.Provider, { value: api }, children));
});
var Point = /* @__PURE__ */ import_react.forwardRef(({ children, ...props }, ref) => {
	import_react.useMemo(() => extend({ PositionPoint }), []);
	const group = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => group.current, []);
	const { subscribe, getParent } = import_react.useContext(context$3);
	import_react.useLayoutEffect(() => subscribe(group), []);
	return /*#__PURE__*/ import_react.createElement("positionPoint", _extends$1({
		instance: getParent(),
		instanceKey: group,
		ref: group
	}, props), children);
});
/**
* Buffer implementation, relies on complete buffers of the correct number, leaves it to the user to update them
*/
var PointsBuffer = /* @__PURE__ */ import_react.forwardRef(({ children, positions, colors, sizes, stride = 3, ...props }, forwardedRef) => {
	const pointsRef = import_react.useRef(null);
	import_react.useImperativeHandle(forwardedRef, () => pointsRef.current, []);
	useFrame(() => {
		const attr = pointsRef.current.geometry.attributes;
		attr.position.needsUpdate = true;
		if (colors) attr.color.needsUpdate = true;
		if (sizes) attr.size.needsUpdate = true;
	});
	return /*#__PURE__*/ import_react.createElement("points", _extends$1({ ref: pointsRef }, props), /*#__PURE__*/ import_react.createElement("bufferGeometry", null, /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-position",
		args: [positions, stride],
		usage: DynamicDrawUsage
	}), colors && /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-color",
		args: [colors, stride],
		count: colors.length / stride,
		usage: 35048
	}), sizes && /*#__PURE__*/ import_react.createElement("bufferAttribute", {
		attach: "attributes-size",
		args: [sizes, 1],
		count: sizes.length / stride,
		usage: 35048
	})), children);
});
var Points = /* @__PURE__ */ import_react.forwardRef((props, forwardedRef) => {
	if (props.positions instanceof Float32Array) return /*#__PURE__*/ import_react.createElement(PointsBuffer, _extends$1({}, props, { ref: forwardedRef }));
	else return /*#__PURE__*/ import_react.createElement(PointsInstances, _extends$1({}, props, { ref: forwardedRef }));
});
//#endregion
//#region node_modules/@react-three/drei/core/Segments.js
var context$2 = /* @__PURE__ */ import_react.createContext(null);
var Segments = /* @__PURE__ */ import_react.forwardRef((props, forwardedRef) => {
	import_react.useMemo(() => extend({ SegmentObject }), []);
	const { limit = 1e3, lineWidth = 1, children, ...rest } = props;
	const [segments, setSegments] = import_react.useState([]);
	const [line] = import_react.useState(() => new Line2());
	const [material] = import_react.useState(() => new LineMaterial());
	const [geometry] = import_react.useState(() => new LineSegmentsGeometry());
	const [resolution] = import_react.useState(() => new Vector2(512, 512));
	const [positions] = import_react.useState(() => Array(limit * 6).fill(0));
	const [colors] = import_react.useState(() => Array(limit * 6).fill(0));
	const api = import_react.useMemo(() => ({ subscribe: (ref) => {
		setSegments((segments) => [...segments, ref]);
		return () => setSegments((segments) => segments.filter((item) => item.current !== ref.current));
	} }), []);
	useFrame(() => {
		for (let i = 0; i < limit; i++) {
			var _segments$i;
			const segment = (_segments$i = segments[i]) == null ? void 0 : _segments$i.current;
			if (segment) {
				positions[i * 6 + 0] = segment.start.x;
				positions[i * 6 + 1] = segment.start.y;
				positions[i * 6 + 2] = segment.start.z;
				positions[i * 6 + 3] = segment.end.x;
				positions[i * 6 + 4] = segment.end.y;
				positions[i * 6 + 5] = segment.end.z;
				colors[i * 6 + 0] = segment.color.r;
				colors[i * 6 + 1] = segment.color.g;
				colors[i * 6 + 2] = segment.color.b;
				colors[i * 6 + 3] = segment.color.r;
				colors[i * 6 + 4] = segment.color.g;
				colors[i * 6 + 5] = segment.color.b;
			}
		}
		geometry.setColors(colors);
		geometry.setPositions(positions);
		line.computeLineDistances();
	});
	return /*#__PURE__*/ import_react.createElement("primitive", {
		object: line,
		ref: forwardedRef
	}, /*#__PURE__*/ import_react.createElement("primitive", {
		object: geometry,
		attach: "geometry"
	}), /*#__PURE__*/ import_react.createElement("primitive", _extends$1({
		object: material,
		attach: "material",
		vertexColors: true,
		resolution,
		linewidth: lineWidth
	}, rest)), /*#__PURE__*/ import_react.createElement(context$2.Provider, { value: api }, children));
});
var SegmentObject = class {
	constructor() {
		this.color = new Color("white");
		this.start = new Vector3(0, 0, 0);
		this.end = new Vector3(0, 0, 0);
	}
};
var normPos = (pos) => pos instanceof Vector3 ? pos : new Vector3(...typeof pos === "number" ? [
	pos,
	pos,
	pos
] : pos);
var Segment = /* @__PURE__ */ import_react.forwardRef(({ color, start, end }, forwardedRef) => {
	const api = import_react.useContext(context$2);
	if (!api) throw "Segment must used inside Segments component.";
	const ref = import_react.useRef(null);
	import_react.useImperativeHandle(forwardedRef, () => ref.current, []);
	import_react.useLayoutEffect(() => api.subscribe(ref), []);
	return /*#__PURE__*/ import_react.createElement("segmentObject", {
		ref,
		color,
		start: normPos(start),
		end: normPos(end)
	});
});
//#endregion
//#region node_modules/@react-three/drei/core/Detailed.js
var Detailed = /* @__PURE__ */ import_react.forwardRef(({ children, hysteresis = 0, distances, ...props }, ref) => {
	const lodRef = import_react.useRef(null);
	import_react.useImperativeHandle(ref, () => lodRef.current, []);
	import_react.useLayoutEffect(() => {
		const { current: lod } = lodRef;
		lod.levels.length = 0;
		lod.children.forEach((object, index) => lod.levels.push({
			object,
			hysteresis,
			distance: distances[index]
		}));
	});
	useFrame((state) => {
		var _lodRef$current;
		return (_lodRef$current = lodRef.current) == null ? void 0 : _lodRef$current.update(state.camera);
	});
	return /*#__PURE__*/ import_react.createElement("lOD", _extends$1({ ref: lodRef }, props), children);
});
//#endregion
//#region node_modules/@react-three/drei/core/Preload.js
function Preload({ all, scene, camera }) {
	const gl = useThree(({ gl }) => gl);
	const dCamera = useThree(({ camera }) => camera);
	const dScene = useThree(({ scene }) => scene);
	import_react.useLayoutEffect(() => {
		const invisible = [];
		if (all) (scene || dScene).traverse((object) => {
			if (object.visible === false) {
				invisible.push(object);
				object.visible = true;
			}
		});
		gl.compile(scene || dScene, camera || dCamera);
		const cubeRenderTarget = new WebGLCubeRenderTarget(128);
		new CubeCamera$1(.01, 1e5, cubeRenderTarget).update(gl, scene || dScene);
		cubeRenderTarget.dispose();
		invisible.forEach((object) => object.visible = false);
	}, []);
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/BakeShadows.js
function BakeShadows() {
	const gl = useThree((state) => state.gl);
	(0, import_react.useEffect)(() => {
		gl.shadowMap.autoUpdate = false;
		gl.shadowMap.needsUpdate = true;
		return () => {
			gl.shadowMap.autoUpdate = gl.shadowMap.needsUpdate = true;
		};
	}, [gl.shadowMap]);
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/meshBounds.js
var _inverseMatrix = /* @__PURE__ */ new Matrix4();
var _ray = /* @__PURE__ */ new Ray();
var _sphere = /* @__PURE__ */ new Sphere$1();
var _vA = /* @__PURE__ */ new Vector3();
function meshBounds(raycaster, intersects) {
	const geometry = this.geometry;
	const material = this.material;
	const matrixWorld = this.matrixWorld;
	if (material === void 0) return;
	if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
	_sphere.copy(geometry.boundingSphere);
	_sphere.applyMatrix4(matrixWorld);
	if (raycaster.ray.intersectsSphere(_sphere) === false) return;
	_inverseMatrix.copy(matrixWorld).invert();
	_ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix);
	if (geometry.boundingBox !== null && _ray.intersectBox(geometry.boundingBox, _vA) === null) return;
	intersects.push({
		distance: _vA.distanceTo(raycaster.ray.origin),
		point: _vA.clone(),
		object: this
	});
}
//#endregion
//#region node_modules/@react-three/drei/core/AdaptiveDpr.js
function AdaptiveDpr({ pixelated }) {
	const gl = useThree((state) => state.gl);
	const active = useThree((state) => state.internal.active);
	const current = useThree((state) => state.performance.current);
	const initialDpr = useThree((state) => state.viewport.initialDpr);
	const setDpr = useThree((state) => state.setDpr);
	import_react.useEffect(() => {
		const domElement = gl.domElement;
		return () => {
			if (active) setDpr(initialDpr);
			if (pixelated && domElement) domElement.style.imageRendering = "auto";
		};
	}, []);
	import_react.useEffect(() => {
		setDpr(current * initialDpr);
		if (pixelated && gl.domElement) gl.domElement.style.imageRendering = current === 1 ? "auto" : "pixelated";
	}, [current]);
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/AdaptiveEvents.js
function AdaptiveEvents() {
	const get = useThree((state) => state.get);
	const setEvents = useThree((state) => state.setEvents);
	const current = useThree((state) => state.performance.current);
	import_react.useEffect(() => {
		const enabled = get().events.enabled;
		return () => setEvents({ enabled });
	}, []);
	import_react.useEffect(() => setEvents({ enabled: current === 1 }), [current]);
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/PerformanceMonitor.js
var context$1 = /* @__PURE__ */ (0, import_react.createContext)(null);
function PerformanceMonitor({ iterations = 10, ms = 250, threshold = .75, step = .1, factor: _factor = .5, flipflops = Infinity, bounds = (refreshrate) => refreshrate > 100 ? [60, 100] : [40, 60], onIncline, onDecline, onChange, onFallback, children }) {
	const decimalPlacesRatio = Math.pow(10, 0);
	const [api, _] = (0, import_react.useState)(() => ({
		fps: 0,
		index: 0,
		factor: _factor,
		flipped: 0,
		refreshrate: 0,
		fallback: false,
		frames: [],
		averages: [],
		subscriptions: /* @__PURE__ */ new Map(),
		subscribe: (ref) => {
			const key = Symbol();
			api.subscriptions.set(key, ref.current);
			return () => void api.subscriptions.delete(key);
		}
	}));
	let lastFactor = 0;
	useFrame(() => {
		const { frames, averages } = api;
		if (api.fallback) return;
		if (averages.length < iterations) {
			frames.push(performance.now());
			const msPassed = frames[frames.length - 1] - frames[0];
			if (msPassed >= ms) {
				api.fps = Math.round(frames.length / msPassed * 1e3 * decimalPlacesRatio) / decimalPlacesRatio;
				api.refreshrate = Math.max(api.refreshrate, api.fps);
				averages[api.index++ % iterations] = api.fps;
				if (averages.length === iterations) {
					const [lower, upper] = bounds(api.refreshrate);
					const upperBounds = averages.filter((value) => value >= upper);
					const lowerBounds = averages.filter((value) => value < lower);
					if (upperBounds.length > iterations * threshold) {
						api.factor = Math.min(1, api.factor + step);
						api.flipped++;
						if (onIncline) onIncline(api);
						api.subscriptions.forEach((value) => value.onIncline && value.onIncline(api));
					}
					if (lowerBounds.length > iterations * threshold) {
						api.factor = Math.max(0, api.factor - step);
						api.flipped++;
						if (onDecline) onDecline(api);
						api.subscriptions.forEach((value) => value.onDecline && value.onDecline(api));
					}
					if (lastFactor !== api.factor) {
						lastFactor = api.factor;
						if (onChange) onChange(api);
						api.subscriptions.forEach((value) => value.onChange && value.onChange(api));
					}
					if (api.flipped > flipflops && !api.fallback) {
						api.fallback = true;
						if (onFallback) onFallback(api);
						api.subscriptions.forEach((value) => value.onFallback && value.onFallback(api));
					}
					api.averages = [];
				}
				api.frames = [];
			}
		}
	});
	return /*#__PURE__*/ import_react.createElement(context$1.Provider, { value: api }, children);
}
function usePerformanceMonitor({ onIncline, onDecline, onChange, onFallback }) {
	const api = (0, import_react.useContext)(context$1);
	const ref = (0, import_react.useRef)({
		onIncline,
		onDecline,
		onChange,
		onFallback
	});
	(0, import_react.useLayoutEffect)(() => {
		ref.current.onIncline = onIncline;
		ref.current.onDecline = onDecline;
		ref.current.onChange = onChange;
		ref.current.onFallback = onFallback;
	}, [
		onIncline,
		onDecline,
		onChange,
		onFallback
	]);
	(0, import_react.useLayoutEffect)(() => api.subscribe(ref), [api]);
}
//#endregion
//#region node_modules/@react-three/drei/core/RenderTexture.js
var RenderTexture = /* @__PURE__ */ import_react.forwardRef(({ children, compute, width, height, samples = 8, renderPriority = 0, eventPriority = 0, frames = Infinity, stencilBuffer = false, depthBuffer = true, generateMipmaps = false, ...props }, forwardRef) => {
	const { size, viewport } = useThree();
	const fbo = useFBO((width || size.width) * viewport.dpr, (height || size.height) * viewport.dpr, {
		samples,
		stencilBuffer,
		depthBuffer,
		generateMipmaps
	});
	const [vScene] = import_react.useState(() => new Scene());
	const uvCompute = import_react.useCallback((event, state, previous) => {
		var _fbo$texture, _previous$previousRoo;
		let parent = (_fbo$texture = fbo.texture) == null || (_fbo$texture = _fbo$texture.__r3f.parent) == null ? void 0 : _fbo$texture.object;
		while (parent && !(parent instanceof Object3D)) {
			var _parent$__r3f$parent;
			parent = (_parent$__r3f$parent = parent.__r3f.parent) == null ? void 0 : _parent$__r3f$parent.object;
		}
		if (!parent) return false;
		if (!previous.raycaster.camera) previous.events.compute(event, previous, (_previous$previousRoo = previous.previousRoot) == null ? void 0 : _previous$previousRoo.getState());
		const [intersection] = previous.raycaster.intersectObject(parent);
		if (!intersection) return false;
		const uv = intersection.uv;
		if (!uv) return false;
		state.raycaster.setFromCamera(state.pointer.set(uv.x * 2 - 1, uv.y * 2 - 1), state.camera);
	}, []);
	import_react.useImperativeHandle(forwardRef, () => fbo.texture, [fbo]);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, createPortal(/*#__PURE__*/ import_react.createElement(Container$2, {
		renderPriority,
		frames,
		fbo
	}, children, /*#__PURE__*/ import_react.createElement("group", { onPointerOver: () => null })), vScene, { events: {
		compute: compute || uvCompute,
		priority: eventPriority
	} }), /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: fbo.texture }, props)));
});
function Container$2({ frames, renderPriority, children, fbo }) {
	let count = 0;
	let oldAutoClear;
	let oldXrEnabled;
	let oldRenderTarget;
	let oldIsPresenting;
	useFrame((state) => {
		if (frames === Infinity || count < frames) {
			oldAutoClear = state.gl.autoClear;
			oldXrEnabled = state.gl.xr.enabled;
			oldRenderTarget = state.gl.getRenderTarget();
			oldIsPresenting = state.gl.xr.isPresenting;
			state.gl.autoClear = true;
			state.gl.xr.enabled = false;
			state.gl.xr.isPresenting = false;
			state.gl.setRenderTarget(fbo);
			state.gl.render(state.scene, state.camera);
			state.gl.setRenderTarget(oldRenderTarget);
			state.gl.autoClear = oldAutoClear;
			state.gl.xr.enabled = oldXrEnabled;
			state.gl.xr.isPresenting = oldIsPresenting;
			count++;
		}
	}, renderPriority);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children);
}
//#endregion
//#region node_modules/@react-three/drei/core/RenderCubeTexture.js
var RenderCubeTexture = /* @__PURE__ */ import_react.forwardRef(({ children, compute, renderPriority = -1, eventPriority = 0, frames = Infinity, stencilBuffer = false, depthBuffer = true, generateMipmaps = false, resolution = 896, near = .1, far = 1e3, flip = false, position, rotation, scale, quaternion, matrix, matrixAutoUpdate, ...props }, forwardRef) => {
	const { size, viewport } = useThree();
	const camera = import_react.useRef(null);
	const fbo = import_react.useMemo(() => {
		const fbo = new WebGLCubeRenderTarget(Math.max((resolution || size.width) * viewport.dpr, (resolution || size.height) * viewport.dpr), {
			stencilBuffer,
			depthBuffer,
			generateMipmaps
		});
		fbo.texture.isRenderTargetTexture = !flip;
		fbo.texture.flipY = true;
		fbo.texture.type = HalfFloatType;
		return fbo;
	}, [resolution, flip]);
	import_react.useEffect(() => {
		return () => fbo.dispose();
	}, [fbo]);
	const [vScene] = import_react.useState(() => new Scene());
	import_react.useImperativeHandle(forwardRef, () => ({
		scene: vScene,
		fbo,
		camera: camera.current
	}), [fbo]);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, createPortal(/*#__PURE__*/ import_react.createElement(Container$1, {
		renderPriority,
		frames,
		camera
	}, children, /*#__PURE__*/ import_react.createElement("group", { onPointerOver: () => null })), vScene, { events: {
		compute,
		priority: eventPriority
	} }), /*#__PURE__*/ import_react.createElement("primitive", _extends$1({ object: fbo.texture }, props)), /*#__PURE__*/ import_react.createElement("cubeCamera", {
		ref: camera,
		args: [
			near,
			far,
			fbo
		],
		position,
		rotation,
		scale,
		quaternion,
		matrix,
		matrixAutoUpdate
	}));
});
function Container$1({ frames, renderPriority, children, camera }) {
	let count = 0;
	useFrame((state) => {
		if (frames === Infinity || count < frames) {
			camera.current.update(state.gl, state.scene);
			count++;
		}
	}, renderPriority);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children);
}
//#endregion
//#region node_modules/@react-three/drei/core/Mask.js
var Mask = /* @__PURE__ */ import_react.forwardRef(({ id = 1, colorWrite = false, depthWrite = false, ...props }, fref) => {
	const ref = import_react.useRef(null);
	const spread = import_react.useMemo(() => ({
		colorWrite,
		depthWrite,
		stencilWrite: true,
		stencilRef: id,
		stencilFunc: 519,
		stencilFail: ReplaceStencilOp,
		stencilZFail: ReplaceStencilOp,
		stencilZPass: ReplaceStencilOp
	}), [
		id,
		colorWrite,
		depthWrite
	]);
	import_react.useLayoutEffect(() => {
		Object.assign(ref.current.material, spread);
	});
	import_react.useImperativeHandle(fref, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement("mesh", _extends$1({
		ref,
		renderOrder: -id
	}, props));
});
function useMask(id, inverse = false) {
	return {
		stencilWrite: true,
		stencilRef: id,
		stencilFunc: inverse ? 517 : 514,
		stencilFail: KeepStencilOp,
		stencilZFail: KeepStencilOp,
		stencilZPass: KeepStencilOp
	};
}
//#endregion
//#region node_modules/@react-three/drei/core/Fisheye.js
function Fisheye({ renderPriority = 1, zoom = 0, segments = 64, children, resolution = 896, ...props }) {
	const sphere = import_react.useRef(null);
	const cubeApi = import_react.useRef(null);
	const { width, height } = useThree((state) => state.size);
	const [orthoC] = import_react.useState(() => new OrthographicCamera$1());
	import_react.useLayoutEffect(() => {
		orthoC.position.set(0, 0, 100);
		orthoC.zoom = 100;
		orthoC.left = width / -2;
		orthoC.right = width / 2;
		orthoC.top = height / 2;
		orthoC.bottom = height / -2;
		orthoC.updateProjectionMatrix();
	}, [width, height]);
	const radius = Math.sqrt(width * width + height * height) / 100 * (.5 + zoom / 2);
	const normal = new Vector3();
	const sph = new Sphere$1(new Vector3(), radius);
	const normalMatrix = new Matrix3();
	const compute = import_react.useCallback((event, state, prev) => {
		state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
		state.raycaster.setFromCamera(state.pointer, orthoC);
		if (!state.raycaster.ray.intersectSphere(sph, normal)) return;
		else normal.normalize();
		normalMatrix.getNormalMatrix(cubeApi.current.camera.matrixWorld);
		cubeApi.current.camera.getWorldPosition(state.raycaster.ray.origin);
		state.raycaster.ray.direction.set(0, 0, 1).reflect(normal);
		state.raycaster.ray.direction.x *= -1;
		state.raycaster.ray.direction.applyNormalMatrix(normalMatrix).multiplyScalar(-1);
	}, []);
	useFrame((state) => {
		if (renderPriority) state.gl.render(sphere.current, orthoC);
	}, renderPriority);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("mesh", _extends$1({ ref: sphere }, props, { scale: radius }), /*#__PURE__*/ import_react.createElement("sphereGeometry", { args: [
		1,
		segments,
		segments
	] }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", null, /*#__PURE__*/ import_react.createElement(RenderCubeTexture, {
		compute,
		attach: "envMap",
		flip: true,
		resolution,
		ref: cubeApi
	}, children, /*#__PURE__*/ import_react.createElement(UpdateCubeCamera, { api: cubeApi })))));
}
function UpdateCubeCamera({ api }) {
	const t = new Vector3();
	const r = new Quaternion();
	const s = new Vector3();
	const e = new Euler(0, Math.PI, 0);
	useFrame((state) => {
		state.camera.matrixWorld.decompose(t, r, s);
		api.current.camera.position.copy(t);
		api.current.camera.quaternion.setFromEuler(e).premultiply(r);
	});
	return null;
}
//#endregion
//#region node_modules/@react-three/drei/core/MeshPortalMaterial.js
var PortalMaterialImpl = /* @__PURE__ */ shaderMaterial({
	blur: 0,
	map: null,
	sdf: null,
	blend: 0,
	size: 0,
	resolution: /* @__PURE__ */ new Vector2()
}, `varying vec2 vUv;
   void main() {
     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
     vUv = uv;
   }`, `uniform sampler2D sdf;
   uniform sampler2D map;
   uniform float blur;
   uniform float size;
   uniform float time;
   uniform vec2 resolution;
   varying vec2 vUv;
   #include 
   void main() {
     vec2 uv = gl_FragCoord.xy / resolution.xy;
     vec4 t = texture2D(map, uv);
     float k = blur;
     float d = texture2D(sdf, vUv).r/size;
     float alpha = 1.0 - smoothstep(0.0, 1.0, clamp(d/k + 1.0, 0.0, 1.0));
     gl_FragColor = vec4(t.rgb, blur == 0.0 ? t.a : t.a * alpha);
     #include 
     #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
   }`);
var MeshPortalMaterial = /* @__PURE__ */ import_react.forwardRef(({ children, events = void 0, blur = 0, eventPriority = 0, renderPriority = 0, worldUnits = false, resolution = 512, ...props }, fref) => {
	extend({ PortalMaterialImpl });
	const ref = import_react.useRef(null);
	const { scene, gl, size, viewport, setEvents } = useThree();
	const maskRenderTarget = useFBO(resolution, resolution);
	const [priority, setPriority] = import_react.useState(0);
	useFrame(() => {
		const p = ref.current.blend > 0 ? Math.max(1, renderPriority) : 0;
		if (priority !== p) setPriority(p);
	});
	import_react.useEffect(() => {
		if (events !== void 0) setEvents({ enabled: !events });
	}, [events]);
	const [visible, setVisible] = import_react.useState(true);
	const parent = useIntersect(setVisible);
	import_react.useLayoutEffect(() => {
		var _ref$current;
		parent.current = (_ref$current = ref.current) == null || (_ref$current = _ref$current.__r3f.parent) == null ? void 0 : _ref$current.object;
	}, []);
	import_react.useLayoutEffect(() => {
		if (!parent.current) return;
		if (blur && ref.current.sdf === null) {
			const tempMesh = new Mesh(parent.current.geometry, new MeshBasicMaterial());
			const boundingBox = new Box3().setFromBufferAttribute(tempMesh.geometry.attributes.position);
			const orthoCam = new OrthographicCamera$1(boundingBox.min.x * (1 + 2 / resolution), boundingBox.max.x * (1 + 2 / resolution), boundingBox.max.y * (1 + 2 / resolution), boundingBox.min.y * (1 + 2 / resolution), .1, 1e3);
			orthoCam.position.set(0, 0, 1);
			orthoCam.lookAt(0, 0, 0);
			gl.setRenderTarget(maskRenderTarget);
			gl.render(tempMesh, orthoCam);
			const sdf = makeSDFGenerator(resolution, resolution, gl)(maskRenderTarget.texture);
			const readSdf = new Float32Array(resolution * resolution);
			gl.readRenderTargetPixels(sdf, 0, 0, resolution, resolution, readSdf);
			let min = Infinity;
			for (let i = 0; i < readSdf.length; i++) if (readSdf[i] < min) min = readSdf[i];
			min = -min;
			ref.current.size = min;
			ref.current.sdf = sdf.texture;
			gl.setRenderTarget(null);
		}
	}, [resolution, blur]);
	import_react.useImperativeHandle(fref, () => ref.current);
	const compute = import_react.useCallback((event, state, previous) => {
		var _ref$current2;
		if (!parent.current) return false;
		state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
		state.raycaster.setFromCamera(state.pointer, state.camera);
		if (((_ref$current2 = ref.current) == null ? void 0 : _ref$current2.blend) === 0) {
			const [intersection] = state.raycaster.intersectObject(parent.current);
			if (!intersection) {
				state.raycaster.camera = void 0;
				return false;
			}
		}
	}, []);
	return /*#__PURE__*/ import_react.createElement("portalMaterialImpl", _extends$1({
		ref,
		blur,
		blend: 0,
		resolution: [size.width * viewport.dpr, size.height * viewport.dpr],
		attach: "material"
	}, props), /*#__PURE__*/ import_react.createElement(RenderTexture, {
		attach: "map",
		frames: visible ? Infinity : 0,
		eventPriority,
		renderPriority,
		compute
	}, children, /*#__PURE__*/ import_react.createElement(ManagePortalScene, {
		events,
		rootScene: scene,
		priority,
		material: ref,
		worldUnits
	})));
});
function ManagePortalScene({ events = void 0, rootScene, material, priority, worldUnits }) {
	const scene = useThree((state) => state.scene);
	const setEvents = useThree((state) => state.setEvents);
	const buffer1 = useFBO();
	const buffer2 = useFBO();
	import_react.useLayoutEffect(() => {
		scene.matrixAutoUpdate = false;
	}, []);
	import_react.useEffect(() => {
		if (events !== void 0) setEvents({ enabled: events });
	}, [events]);
	const [quad, blend] = import_react.useMemo(() => {
		const blend = { value: 0 };
		return [new FullScreenQuad(new ShaderMaterial({
			uniforms: {
				a: { value: buffer1.texture },
				b: { value: buffer2.texture },
				blend
			},
			vertexShader: `
          varying vec2 vUv;
          void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
          }`,
			fragmentShader: `
          uniform sampler2D a;
          uniform sampler2D b;
          uniform float blend;
          varying vec2 vUv;
          #include 
          void main() {
            vec4 ta = texture2D(a, vUv);
            vec4 tb = texture2D(b, vUv);
            gl_FragColor = mix(tb, ta, blend);
            #include 
            #include <${version$1 >= 154 ? "colorspace_fragment" : "encodings_fragment"}>
          }`
		})), blend];
	}, []);
	useFrame((state) => {
		var _material$current;
		let parent = material == null || (_material$current = material.current) == null || (_material$current = _material$current.__r3f.parent) == null ? void 0 : _material$current.object;
		if (parent) {
			if (!worldUnits) {
				var _material$current2;
				if (priority && ((_material$current2 = material.current) == null ? void 0 : _material$current2.blend) === 1) parent.updateWorldMatrix(true, false);
				scene.matrixWorld.copy(parent.matrixWorld);
			} else scene.matrixWorld.identity();
			if (priority) {
				var _material$current3, _material$current4, _material$current5;
				if (((_material$current3 = material.current) == null ? void 0 : _material$current3.blend) > 0 && ((_material$current4 = material.current) == null ? void 0 : _material$current4.blend) < 1) {
					blend.value = material.current.blend;
					state.gl.setRenderTarget(buffer1);
					state.gl.render(scene, state.camera);
					state.gl.setRenderTarget(buffer2);
					state.gl.render(rootScene, state.camera);
					state.gl.setRenderTarget(null);
					quad.render(state.gl);
				} else if (((_material$current5 = material.current) == null ? void 0 : _material$current5.blend) === 1) state.gl.render(scene, state.camera);
			}
		}
	}, priority);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null);
}
var makeSDFGenerator = (clientWidth, clientHeight, renderer) => {
	let finalTarget = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: LinearMipmapLinearFilter,
		magFilter: LinearFilter,
		type: FloatType,
		format: RedFormat,
		generateMipmaps: true
	});
	let outsideRenderTarget = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter
	});
	let insideRenderTarget = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter
	});
	let outsideRenderTarget2 = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter
	});
	let insideRenderTarget2 = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter
	});
	let outsideRenderTargetFinal = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter,
		type: FloatType,
		format: RedFormat
	});
	let insideRenderTargetFinal = new WebGLRenderTarget(clientWidth, clientHeight, {
		minFilter: NearestFilter,
		magFilter: NearestFilter,
		type: FloatType,
		format: RedFormat
	});
	const uvRender = new FullScreenQuad(new ShaderMaterial({
		uniforms: { tex: { value: null } },
		vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
		fragmentShader: `
        uniform sampler2D tex;
        varying vec2 vUv;
        #include 
        void main() {
          gl_FragColor = pack2HalfToRGBA(vUv * (round(texture2D(tex, vUv).x)));
        }`
	}));
	const uvRenderInside = new FullScreenQuad(new ShaderMaterial({
		uniforms: { tex: { value: null } },
		vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
		fragmentShader: `
        uniform sampler2D tex;
        varying vec2 vUv;
        #include 
        void main() {
          gl_FragColor = pack2HalfToRGBA(vUv * (1.0 - round(texture2D(tex, vUv).x)));
        }`
	}));
	const jumpFloodRender = new FullScreenQuad(new ShaderMaterial({
		uniforms: {
			tex: { value: null },
			offset: { value: 0 },
			level: { value: 0 },
			maxSteps: { value: 0 }
		},
		vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
		fragmentShader: `
        varying vec2 vUv;
        uniform sampler2D tex;
        uniform float offset;
        uniform float level;
        uniform float maxSteps;
        #include 
        void main() {
          float closestDist = 9999999.9;
          vec2 closestPos = vec2(0.0);
          for (float x = -1.0; x <= 1.0; x += 1.0) {
            for (float y = -1.0; y <= 1.0; y += 1.0) {
              vec2 voffset = vUv;
              voffset += vec2(x, y) * vec2(${1 / clientWidth}, ${1 / clientHeight}) * offset;
              vec2 pos = unpackRGBATo2Half(texture2D(tex, voffset));
              float dist = distance(pos.xy, vUv);
              if(pos.x != 0.0 && pos.y != 0.0 && dist < closestDist) {
                closestDist = dist;
                closestPos = pos;
              }
            }
          }
          gl_FragColor = pack2HalfToRGBA(closestPos);
        }`
	}));
	const distanceFieldRender = new FullScreenQuad(new ShaderMaterial({
		uniforms: {
			tex: { value: null },
			size: { value: new Vector2(clientWidth, clientHeight) }
		},
		vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
		fragmentShader: `
        varying vec2 vUv;
        uniform sampler2D tex;
        uniform vec2 size;
        #include 
        void main() {
          gl_FragColor = vec4(distance(size * unpackRGBATo2Half(texture2D(tex, vUv)), size * vUv), 0.0, 0.0, 0.0);
        }`
	}));
	const compositeRender = new FullScreenQuad(new ShaderMaterial({
		uniforms: {
			inside: { value: insideRenderTargetFinal.texture },
			outside: { value: outsideRenderTargetFinal.texture },
			tex: { value: null }
		},
		vertexShader: `
        varying vec2 vUv;
        void main() {
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
		fragmentShader: `
        varying vec2 vUv;
        uniform sampler2D inside;
        uniform sampler2D outside;
        uniform sampler2D tex;
        #include 
        void main() {
          float i = texture2D(inside, vUv).x;
          float o =texture2D(outside, vUv).x;
          if (texture2D(tex, vUv).x == 0.0) {
            gl_FragColor = vec4(o, 0.0, 0.0, 0.0);
          } else {
            gl_FragColor = vec4(-i, 0.0, 0.0, 0.0);
          }
        }`
	}));
	return (image) => {
		let ft = finalTarget;
		image.minFilter = NearestFilter;
		image.magFilter = NearestFilter;
		uvRender.material.uniforms.tex.value = image;
		renderer.setRenderTarget(outsideRenderTarget);
		uvRender.render(renderer);
		const passes = Math.ceil(Math.log(Math.max(clientWidth, clientHeight)) / Math.log(2));
		let lastTarget = outsideRenderTarget;
		let target = null;
		for (let i = 0; i < passes; i++) {
			const offset = Math.pow(2, passes - i - 1);
			target = lastTarget === outsideRenderTarget ? outsideRenderTarget2 : outsideRenderTarget;
			jumpFloodRender.material.uniforms.level.value = i;
			jumpFloodRender.material.uniforms.maxSteps.value = passes;
			jumpFloodRender.material.uniforms.offset.value = offset;
			jumpFloodRender.material.uniforms.tex.value = lastTarget.texture;
			renderer.setRenderTarget(target);
			jumpFloodRender.render(renderer);
			lastTarget = target;
		}
		renderer.setRenderTarget(outsideRenderTargetFinal);
		distanceFieldRender.material.uniforms.tex.value = target.texture;
		distanceFieldRender.render(renderer);
		uvRenderInside.material.uniforms.tex.value = image;
		renderer.setRenderTarget(insideRenderTarget);
		uvRenderInside.render(renderer);
		lastTarget = insideRenderTarget;
		for (let i = 0; i < passes; i++) {
			const offset = Math.pow(2, passes - i - 1);
			target = lastTarget === insideRenderTarget ? insideRenderTarget2 : insideRenderTarget;
			jumpFloodRender.material.uniforms.level.value = i;
			jumpFloodRender.material.uniforms.maxSteps.value = passes;
			jumpFloodRender.material.uniforms.offset.value = offset;
			jumpFloodRender.material.uniforms.tex.value = lastTarget.texture;
			renderer.setRenderTarget(target);
			jumpFloodRender.render(renderer);
			lastTarget = target;
		}
		renderer.setRenderTarget(insideRenderTargetFinal);
		distanceFieldRender.material.uniforms.tex.value = target.texture;
		distanceFieldRender.render(renderer);
		renderer.setRenderTarget(ft);
		compositeRender.material.uniforms.tex.value = image;
		compositeRender.render(renderer);
		renderer.setRenderTarget(null);
		return ft;
	};
};
//#endregion
//#region node_modules/tunnel-rat/node_modules/zustand/esm/vanilla.mjs
var createStoreImpl = (createState) => {
	let state;
	const listeners = /* @__PURE__ */ new Set();
	const setState = (partial, replace) => {
		const nextState = typeof partial === "function" ? partial(state) : partial;
		if (!Object.is(nextState, state)) {
			const previousState = state;
			state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
			listeners.forEach((listener) => listener(state, previousState));
		}
	};
	const getState = () => state;
	const getInitialState = () => initialState;
	const subscribe = (listener) => {
		listeners.add(listener);
		return () => listeners.delete(listener);
	};
	const destroy = () => {
		if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected.");
		listeners.clear();
	};
	const api = {
		setState,
		getState,
		getInitialState,
		subscribe,
		destroy
	};
	const initialState = state = createState(setState, getState, api);
	return api;
};
var createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
//#endregion
//#region node_modules/tunnel-rat/node_modules/zustand/esm/index.mjs
var import_with_selector = /* @__PURE__ */ __toESM(require_with_selector(), 1);
var { useDebugValue } = import_react.default;
var { useSyncExternalStoreWithSelector } = import_with_selector.default;
var didWarnAboutEqualityFn = false;
var identity = (arg) => arg;
function useStore(api, selector = identity, equalityFn) {
	if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && equalityFn && !didWarnAboutEqualityFn) {
		console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937");
		didWarnAboutEqualityFn = true;
	}
	const slice = useSyncExternalStoreWithSelector(api.subscribe, api.getState, api.getServerState || api.getInitialState, selector, equalityFn);
	useDebugValue(slice);
	return slice;
}
var createImpl = (createState) => {
	if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && typeof createState !== "function") console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");
	const api = typeof createState === "function" ? createStore(createState) : createState;
	const useBoundStore = (selector, equalityFn) => useStore(api, selector, equalityFn);
	Object.assign(useBoundStore, api);
	return useBoundStore;
};
var create = (createState) => createState ? createImpl(createState) : createImpl;
//#endregion
//#region node_modules/tunnel-rat/dist/index.js
var _window$document, _window$navigator;
/**
* An SSR-friendly useLayoutEffect.
*
* React currently throws a warning when using useLayoutEffect on the server.
* To get around it, we can conditionally useEffect on the server (no-op) and
* useLayoutEffect elsewhere.
*
* @see https://github.com/facebook/react/issues/14927
*/
var useIsomorphicLayoutEffect = typeof window !== "undefined" && ((_window$document = window.document) != null && _window$document.createElement || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === "ReactNative") ? import_react.useLayoutEffect : import_react.useEffect;
function tunnel() {
	const useStore = create((set) => ({
		current: new Array(),
		version: 0,
		set
	}));
	return {
		In: ({ children }) => {
			const set = useStore((state) => state.set);
			const version = useStore((state) => state.version);
			useIsomorphicLayoutEffect(() => {
				set((state) => ({ version: state.version + 1 }));
			}, []);
			useIsomorphicLayoutEffect(() => {
				set(({ current }) => ({ current: [...current, children] }));
				return () => set(({ current }) => ({ current: current.filter((c) => c !== children) }));
			}, [children, version]);
			return null;
		},
		Out: () => {
			const current = useStore((state) => state.current);
			return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, current);
		}
	};
}
//#endregion
//#region node_modules/@react-three/drei/web/View.js
var isOrthographicCamera = (def) => def && def.isOrthographicCamera;
var col = /* @__PURE__ */ new Color();
var tracked = /* @__PURE__ */ tunnel();
function computeContainerPosition(canvasSize, trackRect) {
	const { right, top, left: trackLeft, bottom: trackBottom, width, height } = trackRect;
	const isOffscreen = trackRect.bottom < 0 || top > canvasSize.height || right < 0 || trackRect.left > canvasSize.width;
	const bottom = canvasSize.top + canvasSize.height - trackBottom;
	return {
		position: {
			width,
			height,
			left: trackLeft - canvasSize.left,
			top,
			bottom,
			right
		},
		isOffscreen
	};
}
function prepareSkissor(state, { left, bottom, width, height }) {
	let autoClear;
	const aspect = width / height;
	if (isOrthographicCamera(state.camera)) if (!state.camera.manual) {
		if (state.camera.left !== width / -2 || state.camera.right !== width / 2 || state.camera.top !== height / 2 || state.camera.bottom !== height / -2) {
			Object.assign(state.camera, {
				left: width / -2,
				right: width / 2,
				top: height / 2,
				bottom: height / -2
			});
			state.camera.updateProjectionMatrix();
		}
	} else state.camera.updateProjectionMatrix();
	else if (state.camera.aspect !== aspect) {
		state.camera.aspect = aspect;
		state.camera.updateProjectionMatrix();
	}
	autoClear = state.gl.autoClear;
	state.gl.autoClear = false;
	state.gl.setViewport(left, bottom, width, height);
	state.gl.setScissor(left, bottom, width, height);
	state.gl.setScissorTest(true);
	return autoClear;
}
function finishSkissor(state, autoClear) {
	state.gl.setScissorTest(false);
	state.gl.autoClear = autoClear;
}
function clear(state) {
	state.gl.getClearColor(col);
	state.gl.setClearColor(col, state.gl.getClearAlpha());
	state.gl.clear(true, true);
}
function Container({ visible = true, canvasSize, scene, index, children, frames, rect, track }) {
	const rootState = useThree();
	const [isOffscreen, setOffscreen] = import_react.useState(false);
	let frameCount = 0;
	useFrame((state) => {
		if (frames === Infinity || frameCount <= frames) {
			var _track$current;
			if (track) rect.current = (_track$current = track.current) == null ? void 0 : _track$current.getBoundingClientRect();
			frameCount++;
		}
		if (rect.current) {
			const { position, isOffscreen: _isOffscreen } = computeContainerPosition(canvasSize, rect.current);
			if (isOffscreen !== _isOffscreen) setOffscreen(_isOffscreen);
			if (visible && !isOffscreen && rect.current) {
				const autoClear = prepareSkissor(state, position);
				state.gl.render(children ? state.scene : scene, state.camera);
				finishSkissor(state, autoClear);
			}
		}
	}, index);
	import_react.useLayoutEffect(() => {
		const curRect = rect.current;
		if (curRect && (!visible || !isOffscreen)) {
			const { position } = computeContainerPosition(canvasSize, curRect);
			const autoClear = prepareSkissor(rootState, position);
			clear(rootState);
			finishSkissor(rootState, autoClear);
		}
	}, [visible, isOffscreen]);
	import_react.useEffect(() => {
		if (!track) return;
		const curRect = rect.current;
		const old = rootState.get().events.connected;
		rootState.setEvents({ connected: track.current });
		return () => {
			if (curRect) {
				const { position } = computeContainerPosition(canvasSize, curRect);
				const autoClear = prepareSkissor(rootState, position);
				clear(rootState);
				finishSkissor(rootState, autoClear);
			}
			rootState.setEvents({ connected: old });
		};
	}, [track]);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, children, /*#__PURE__*/ import_react.createElement("group", { onPointerOver: () => null }));
}
var CanvasView = /* @__PURE__ */ import_react.forwardRef(({ track, visible = true, index = 1, id, style, className, frames = Infinity, children, ...props }, fref) => {
	var _rect$current, _rect$current2, _rect$current3, _rect$current4;
	const rect = import_react.useRef(null);
	const { size, scene } = useThree();
	const [virtualScene] = import_react.useState(() => new Scene());
	const [ready, toggle] = import_react.useReducer(() => true, false);
	const compute = import_react.useCallback((event, state) => {
		if (rect.current && track && track.current && event.target === track.current) {
			const { width, height, left, top } = rect.current;
			const x = event.clientX - left;
			const y = event.clientY - top;
			state.pointer.set(x / width * 2 - 1, -(y / height) * 2 + 1);
			state.raycaster.setFromCamera(state.pointer, state.camera);
		}
	}, [rect, track]);
	import_react.useEffect(() => {
		var _track$current2;
		if (track) rect.current = (_track$current2 = track.current) == null ? void 0 : _track$current2.getBoundingClientRect();
		toggle();
	}, [track]);
	return /*#__PURE__*/ import_react.createElement("group", _extends$1({ ref: fref }, props), ready && createPortal(/*#__PURE__*/ import_react.createElement(Container, {
		visible,
		canvasSize: size,
		frames,
		scene,
		track,
		rect,
		index
	}, children), virtualScene, {
		events: {
			compute,
			priority: index
		},
		size: {
			width: (_rect$current = rect.current) == null ? void 0 : _rect$current.width,
			height: (_rect$current2 = rect.current) == null ? void 0 : _rect$current2.height,
			top: (_rect$current3 = rect.current) == null ? void 0 : _rect$current3.top,
			left: (_rect$current4 = rect.current) == null ? void 0 : _rect$current4.left
		}
	}));
});
var HtmlView = /* @__PURE__ */ import_react.forwardRef(({ as: El = "div", id, visible, className, style, index = 1, track, frames = Infinity, children, ...props }, fref) => {
	const uuid = import_react.useId();
	const ref = import_react.useRef(null);
	import_react.useImperativeHandle(fref, () => ref.current);
	return /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement(El, _extends$1({
		ref,
		id,
		className,
		style
	}, props)), /*#__PURE__*/ import_react.createElement(tracked.In, null, /*#__PURE__*/ import_react.createElement(CanvasView, {
		visible,
		key: uuid,
		track: ref,
		frames,
		index
	}, children)));
});
var View = /* @__PURE__ */ (() => {
	const _View = /*#__PURE__*/ import_react.forwardRef((props, fref) => {
		if (!import_react.useContext(context$10)) return /*#__PURE__*/ import_react.createElement(HtmlView, _extends$1({ ref: fref }, props));
		else return /*#__PURE__*/ import_react.createElement(CanvasView, _extends$1({ ref: fref }, props));
	});
	_View.Port = () => /*#__PURE__*/ import_react.createElement(tracked.Out, null);
	return _View;
})();
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/context.js
var context = /* @__PURE__ */ import_react.createContext(null);
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/AxisArrow.js
var vec1$1 = /* @__PURE__ */ new Vector3();
var vec2$1 = /* @__PURE__ */ new Vector3();
var calculateOffset$1 = (clickPoint, normal, rayStart, rayDir) => {
	const e1 = normal.dot(normal);
	const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
	const e3 = normal.dot(rayDir);
	if (e3 === 0) return -e2 / e1;
	vec1$1.copy(rayDir).multiplyScalar(e1 / e3).sub(normal);
	vec2$1.copy(rayDir).multiplyScalar(e2 / e3).add(rayStart).sub(clickPoint);
	return -vec1$1.dot(vec2$1) / vec1$1.dot(vec1$1);
};
var upV$1 = /* @__PURE__ */ new Vector3(0, 1, 0);
var offsetMatrix$1 = /* @__PURE__ */ new Matrix4();
var AxisArrow = ({ direction, axis }) => {
	const { translation, translationLimits, annotations, annotationsClass, depthTest, scale, lineWidth, fixed, axisColors, hoveredColor, opacity, renderOrder, onDragStart, onDrag, onDragEnd, userData } = import_react.useContext(context);
	const camControls = useThree((state) => state.controls);
	const divRef = import_react.useRef(null);
	const objRef = import_react.useRef(null);
	const clickInfo = import_react.useRef(null);
	const offset0 = import_react.useRef(0);
	const [isHovered, setIsHovered] = import_react.useState(false);
	const onPointerDown = import_react.useCallback((e) => {
		if (annotations) {
			divRef.current.innerText = `${translation.current[axis].toFixed(2)}`;
			divRef.current.style.display = "block";
		}
		e.stopPropagation();
		const rotation = new Matrix4().extractRotation(objRef.current.matrixWorld);
		const clickPoint = e.point.clone();
		const origin = new Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
		const dir = direction.clone().applyMatrix4(rotation).normalize();
		clickInfo.current = {
			clickPoint,
			dir
		};
		offset0.current = translation.current[axis];
		onDragStart({
			component: "Arrow",
			axis,
			origin,
			directions: [dir]
		});
		camControls && (camControls.enabled = false);
		e.target.setPointerCapture(e.pointerId);
	}, [
		annotations,
		direction,
		camControls,
		onDragStart,
		translation,
		axis
	]);
	const onPointerMove = import_react.useCallback((e) => {
		e.stopPropagation();
		if (!isHovered) setIsHovered(true);
		if (clickInfo.current) {
			const { clickPoint, dir } = clickInfo.current;
			const [min, max] = (translationLimits == null ? void 0 : translationLimits[axis]) || [void 0, void 0];
			let offset = calculateOffset$1(clickPoint, dir, e.ray.origin, e.ray.direction);
			if (min !== void 0) offset = Math.max(offset, min - offset0.current);
			if (max !== void 0) offset = Math.min(offset, max - offset0.current);
			translation.current[axis] = offset0.current + offset;
			if (annotations) divRef.current.innerText = `${translation.current[axis].toFixed(2)}`;
			offsetMatrix$1.makeTranslation(dir.x * offset, dir.y * offset, dir.z * offset);
			onDrag(offsetMatrix$1);
		}
	}, [
		annotations,
		onDrag,
		isHovered,
		translation,
		translationLimits,
		axis
	]);
	const onPointerUp = import_react.useCallback((e) => {
		if (annotations) divRef.current.style.display = "none";
		e.stopPropagation();
		clickInfo.current = null;
		onDragEnd();
		camControls && (camControls.enabled = true);
		e.target.releasePointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragEnd
	]);
	const onPointerOut = import_react.useCallback((e) => {
		e.stopPropagation();
		setIsHovered(false);
	}, []);
	const { cylinderLength, coneWidth, coneLength, matrixL } = import_react.useMemo(() => {
		const coneWidth = fixed ? lineWidth / scale * 1.6 : scale / 20;
		const coneLength = fixed ? .2 : scale / 5;
		const cylinderLength = fixed ? 1 - coneLength : scale - coneLength;
		const quaternion = new Quaternion().setFromUnitVectors(upV$1, direction.clone().normalize());
		return {
			cylinderLength,
			coneWidth,
			coneLength,
			matrixL: new Matrix4().makeRotationFromQuaternion(quaternion)
		};
	}, [
		direction,
		scale,
		lineWidth,
		fixed
	]);
	const color_ = isHovered ? hoveredColor : axisColors[axis];
	return /*#__PURE__*/ import_react.createElement("group", { ref: objRef }, /*#__PURE__*/ import_react.createElement("group", {
		matrix: matrixL,
		matrixAutoUpdate: false,
		onPointerDown,
		onPointerMove,
		onPointerUp,
		onPointerOut
	}, annotations && /*#__PURE__*/ import_react.createElement(Html, { position: [
		0,
		-coneLength,
		0
	] }, /*#__PURE__*/ import_react.createElement("div", {
		style: {
			display: "none",
			background: "#151520",
			color: "white",
			padding: "6px 8px",
			borderRadius: 7,
			whiteSpace: "nowrap"
		},
		className: annotationsClass,
		ref: divRef
	})), /*#__PURE__*/ import_react.createElement("mesh", {
		visible: false,
		position: [
			0,
			(cylinderLength + coneLength) / 2,
			0
		],
		userData
	}, /*#__PURE__*/ import_react.createElement("cylinderGeometry", { args: [
		coneWidth * 1.4,
		coneWidth * 1.4,
		cylinderLength + coneLength,
		8,
		1
	] })), /*#__PURE__*/ import_react.createElement(Line, {
		transparent: true,
		raycast: () => null,
		depthTest,
		points: [
			0,
			0,
			0,
			0,
			cylinderLength,
			0
		],
		lineWidth,
		side: 2,
		color: color_,
		opacity,
		polygonOffset: true,
		renderOrder,
		polygonOffsetFactor: -10,
		fog: false
	}), /*#__PURE__*/ import_react.createElement("mesh", {
		raycast: () => null,
		position: [
			0,
			cylinderLength + coneLength / 2,
			0
		],
		renderOrder
	}, /*#__PURE__*/ import_react.createElement("coneGeometry", { args: [
		coneWidth,
		coneLength,
		24,
		1
	] }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		depthTest,
		color: color_,
		opacity,
		polygonOffset: true,
		polygonOffsetFactor: -10,
		fog: false
	}))));
};
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/AxisRotator.js
var clickDir = /* @__PURE__ */ new Vector3();
var intersectionDir = /* @__PURE__ */ new Vector3();
var toDegrees = (radians) => radians * 180 / Math.PI;
var toRadians = (degrees) => degrees * Math.PI / 180;
var calculateAngle = (clickPoint, intersectionPoint, origin, e1, e2) => {
	clickDir.copy(clickPoint).sub(origin);
	intersectionDir.copy(intersectionPoint).sub(origin);
	const dote1e1 = e1.dot(e1);
	const dote2e2 = e2.dot(e2);
	const uClick = clickDir.dot(e1) / dote1e1;
	const vClick = clickDir.dot(e2) / dote2e2;
	const uIntersection = intersectionDir.dot(e1) / dote1e1;
	const vIntersection = intersectionDir.dot(e2) / dote2e2;
	return Math.atan2(vIntersection, uIntersection) - Math.atan2(vClick, uClick);
};
var fmod = (num, denom) => {
	let k = Math.floor(num / denom);
	k = k < 0 ? k + 1 : k;
	return num - k * denom;
};
var minimizeAngle = (angle) => {
	let result = fmod(angle, 2 * Math.PI);
	if (Math.abs(result) < 1e-6) return 0;
	if (result < 0) result += 2 * Math.PI;
	return result;
};
var rotMatrix = /* @__PURE__ */ new Matrix4();
var posNew = /* @__PURE__ */ new Vector3();
var ray$1 = /* @__PURE__ */ new Ray();
var intersection$1 = /* @__PURE__ */ new Vector3();
var AxisRotator = ({ dir1, dir2, axis }) => {
	const { rotationLimits, annotations, annotationsClass, depthTest, scale, lineWidth, fixed, axisColors, hoveredColor, renderOrder, opacity, onDragStart, onDrag, onDragEnd, userData } = import_react.useContext(context);
	const camControls = useThree((state) => state.controls);
	const divRef = import_react.useRef(null);
	const objRef = import_react.useRef(null);
	const angle0 = import_react.useRef(0);
	const angle = import_react.useRef(0);
	const clickInfo = import_react.useRef(null);
	const [isHovered, setIsHovered] = import_react.useState(false);
	const onPointerDown = import_react.useCallback((e) => {
		if (annotations) {
			divRef.current.innerText = `${toDegrees(angle.current).toFixed(0)}º`;
			divRef.current.style.display = "block";
		}
		e.stopPropagation();
		const clickPoint = e.point.clone();
		const origin = new Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
		const e1 = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 0).normalize();
		const e2 = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 1).normalize();
		const normal = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 2).normalize();
		clickInfo.current = {
			clickPoint,
			origin,
			e1,
			e2,
			normal,
			plane: new Plane$1().setFromNormalAndCoplanarPoint(normal, origin)
		};
		onDragStart({
			component: "Rotator",
			axis,
			origin,
			directions: [
				e1,
				e2,
				normal
			]
		});
		camControls && (camControls.enabled = false);
		e.target.setPointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragStart,
		axis
	]);
	const onPointerMove = import_react.useCallback((e) => {
		e.stopPropagation();
		if (!isHovered) setIsHovered(true);
		if (clickInfo.current) {
			const { clickPoint, origin, e1, e2, normal, plane } = clickInfo.current;
			const [min, max] = (rotationLimits == null ? void 0 : rotationLimits[axis]) || [void 0, void 0];
			ray$1.copy(e.ray);
			ray$1.intersectPlane(plane, intersection$1);
			ray$1.direction.negate();
			ray$1.intersectPlane(plane, intersection$1);
			let deltaAngle = calculateAngle(clickPoint, intersection$1, origin, e1, e2);
			let degrees = toDegrees(deltaAngle);
			if (e.shiftKey) {
				degrees = Math.round(degrees / 10) * 10;
				deltaAngle = toRadians(degrees);
			}
			if (min !== void 0 && max !== void 0 && max - min < 2 * Math.PI) {
				deltaAngle = minimizeAngle(deltaAngle);
				deltaAngle = deltaAngle > Math.PI ? deltaAngle - 2 * Math.PI : deltaAngle;
				deltaAngle = MathUtils.clamp(deltaAngle, min - angle0.current, max - angle0.current);
				angle.current = angle0.current + deltaAngle;
			} else {
				angle.current = minimizeAngle(angle0.current + deltaAngle);
				angle.current = angle.current > Math.PI ? angle.current - 2 * Math.PI : angle.current;
			}
			if (annotations) {
				degrees = toDegrees(angle.current);
				divRef.current.innerText = `${degrees.toFixed(0)}º`;
			}
			rotMatrix.makeRotationAxis(normal, deltaAngle);
			posNew.copy(origin).applyMatrix4(rotMatrix).sub(origin).negate();
			rotMatrix.setPosition(posNew);
			onDrag(rotMatrix);
		}
	}, [
		annotations,
		onDrag,
		isHovered,
		rotationLimits,
		axis
	]);
	const onPointerUp = import_react.useCallback((e) => {
		if (annotations) divRef.current.style.display = "none";
		e.stopPropagation();
		angle0.current = angle.current;
		clickInfo.current = null;
		onDragEnd();
		camControls && (camControls.enabled = true);
		e.target.releasePointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragEnd
	]);
	const onPointerOut = import_react.useCallback((e) => {
		e.stopPropagation();
		setIsHovered(false);
	}, []);
	const matrixL = import_react.useMemo(() => {
		const dir1N = dir1.clone().normalize();
		const dir2N = dir2.clone().normalize();
		return new Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
	}, [dir1, dir2]);
	const r = fixed ? .65 : scale * .65;
	const arc = import_react.useMemo(() => {
		const segments = 32;
		const points = [];
		for (let j = 0; j <= segments; j++) {
			const angle = j * (Math.PI / 2) / segments;
			points.push(new Vector3(Math.cos(angle) * r, Math.sin(angle) * r, 0));
		}
		return points;
	}, [r]);
	return /*#__PURE__*/ import_react.createElement("group", {
		ref: objRef,
		onPointerDown,
		onPointerMove,
		onPointerUp,
		onPointerOut,
		matrix: matrixL,
		matrixAutoUpdate: false
	}, annotations && /*#__PURE__*/ import_react.createElement(Html, { position: [
		r,
		r,
		0
	] }, /*#__PURE__*/ import_react.createElement("div", {
		style: {
			display: "none",
			background: "#151520",
			color: "white",
			padding: "6px 8px",
			borderRadius: 7,
			whiteSpace: "nowrap"
		},
		className: annotationsClass,
		ref: divRef
	})), /*#__PURE__*/ import_react.createElement(Line, {
		points: arc,
		lineWidth: lineWidth * 4,
		visible: false,
		userData
	}), /*#__PURE__*/ import_react.createElement(Line, {
		transparent: true,
		raycast: () => null,
		depthTest,
		points: arc,
		lineWidth,
		side: 2,
		color: isHovered ? hoveredColor : axisColors[axis],
		opacity,
		polygonOffset: true,
		polygonOffsetFactor: -10,
		renderOrder,
		fog: false
	}));
};
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/PlaneSlider.js
var decomposeIntoBasis = (e1, e2, offset) => {
	const i1 = Math.abs(e1.x) >= Math.abs(e1.y) && Math.abs(e1.x) >= Math.abs(e1.z) ? 0 : Math.abs(e1.y) >= Math.abs(e1.x) && Math.abs(e1.y) >= Math.abs(e1.z) ? 1 : 2;
	const e2DegrowthOrder = [
		0,
		1,
		2
	].sort((a, b) => Math.abs(e2.getComponent(b)) - Math.abs(e2.getComponent(a)));
	const i2 = i1 === e2DegrowthOrder[0] ? e2DegrowthOrder[1] : e2DegrowthOrder[0];
	const a1 = e1.getComponent(i1);
	const a2 = e1.getComponent(i2);
	const b1 = e2.getComponent(i1);
	const b2 = e2.getComponent(i2);
	const c1 = offset.getComponent(i1);
	const y = (offset.getComponent(i2) - c1 * (a2 / a1)) / (b2 - b1 * (a2 / a1));
	return [(c1 - y * b1) / a1, y];
};
var ray = /* @__PURE__ */ new Ray();
var intersection = /* @__PURE__ */ new Vector3();
var offsetMatrix = /* @__PURE__ */ new Matrix4();
var PlaneSlider = ({ dir1, dir2, axis }) => {
	const { translation, translationLimits, annotations, annotationsClass, depthTest, scale, lineWidth, fixed, axisColors, hoveredColor, opacity, renderOrder, onDragStart, onDrag, onDragEnd, userData } = import_react.useContext(context);
	const camControls = useThree((state) => state.controls);
	const divRef = import_react.useRef(null);
	const objRef = import_react.useRef(null);
	const clickInfo = import_react.useRef(null);
	const offsetX0 = import_react.useRef(0);
	const offsetY0 = import_react.useRef(0);
	const [isHovered, setIsHovered] = import_react.useState(false);
	const onPointerDown = import_react.useCallback((e) => {
		if (annotations) {
			divRef.current.innerText = `${translation.current[(axis + 1) % 3].toFixed(2)}, ${translation.current[(axis + 2) % 3].toFixed(2)}`;
			divRef.current.style.display = "block";
		}
		e.stopPropagation();
		const clickPoint = e.point.clone();
		const origin = new Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
		const e1 = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 0).normalize();
		const e2 = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 1).normalize();
		const normal = new Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 2).normalize();
		clickInfo.current = {
			clickPoint,
			e1,
			e2,
			plane: new Plane$1().setFromNormalAndCoplanarPoint(normal, origin)
		};
		offsetX0.current = translation.current[(axis + 1) % 3];
		offsetY0.current = translation.current[(axis + 2) % 3];
		onDragStart({
			component: "Slider",
			axis,
			origin,
			directions: [
				e1,
				e2,
				normal
			]
		});
		camControls && (camControls.enabled = false);
		e.target.setPointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragStart,
		axis
	]);
	const onPointerMove = import_react.useCallback((e) => {
		e.stopPropagation();
		if (!isHovered) setIsHovered(true);
		if (clickInfo.current) {
			const { clickPoint, e1, e2, plane } = clickInfo.current;
			const [minX, maxX] = (translationLimits == null ? void 0 : translationLimits[(axis + 1) % 3]) || [void 0, void 0];
			const [minY, maxY] = (translationLimits == null ? void 0 : translationLimits[(axis + 2) % 3]) || [void 0, void 0];
			ray.copy(e.ray);
			ray.intersectPlane(plane, intersection);
			ray.direction.negate();
			ray.intersectPlane(plane, intersection);
			intersection.sub(clickPoint);
			let [offsetX, offsetY] = decomposeIntoBasis(e1, e2, intersection);
			if (minX !== void 0) offsetX = Math.max(offsetX, minX - offsetX0.current);
			if (maxX !== void 0) offsetX = Math.min(offsetX, maxX - offsetX0.current);
			if (minY !== void 0) offsetY = Math.max(offsetY, minY - offsetY0.current);
			if (maxY !== void 0) offsetY = Math.min(offsetY, maxY - offsetY0.current);
			translation.current[(axis + 1) % 3] = offsetX0.current + offsetX;
			translation.current[(axis + 2) % 3] = offsetY0.current + offsetY;
			if (annotations) divRef.current.innerText = `${translation.current[(axis + 1) % 3].toFixed(2)}, ${translation.current[(axis + 2) % 3].toFixed(2)}`;
			offsetMatrix.makeTranslation(offsetX * e1.x + offsetY * e2.x, offsetX * e1.y + offsetY * e2.y, offsetX * e1.z + offsetY * e2.z);
			onDrag(offsetMatrix);
		}
	}, [
		annotations,
		onDrag,
		isHovered,
		translation,
		translationLimits,
		axis
	]);
	const onPointerUp = import_react.useCallback((e) => {
		if (annotations) divRef.current.style.display = "none";
		e.stopPropagation();
		clickInfo.current = null;
		onDragEnd();
		camControls && (camControls.enabled = true);
		e.target.releasePointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragEnd
	]);
	const onPointerOut = import_react.useCallback((e) => {
		e.stopPropagation();
		setIsHovered(false);
	}, []);
	const matrixL = import_react.useMemo(() => {
		const dir1N = dir1.clone().normalize();
		const dir2N = dir2.clone().normalize();
		return new Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
	}, [dir1, dir2]);
	const pos1 = fixed ? 1 / 7 : scale / 7;
	const length = fixed ? .225 : scale * .225;
	const color = isHovered ? hoveredColor : axisColors[axis];
	const points = import_react.useMemo(() => [
		new Vector3(0, 0, 0),
		new Vector3(0, length, 0),
		new Vector3(length, length, 0),
		new Vector3(length, 0, 0),
		new Vector3(0, 0, 0)
	], [length]);
	return /*#__PURE__*/ import_react.createElement("group", {
		ref: objRef,
		matrix: matrixL,
		matrixAutoUpdate: false
	}, annotations && /*#__PURE__*/ import_react.createElement(Html, { position: [
		0,
		0,
		0
	] }, /*#__PURE__*/ import_react.createElement("div", {
		style: {
			display: "none",
			background: "#151520",
			color: "white",
			padding: "6px 8px",
			borderRadius: 7,
			whiteSpace: "nowrap"
		},
		className: annotationsClass,
		ref: divRef
	})), /*#__PURE__*/ import_react.createElement("group", { position: [
		pos1 * 1.7,
		pos1 * 1.7,
		0
	] }, /*#__PURE__*/ import_react.createElement("mesh", {
		visible: true,
		onPointerDown,
		onPointerMove,
		onPointerUp,
		onPointerOut,
		scale: length,
		userData,
		renderOrder
	}, /*#__PURE__*/ import_react.createElement("planeGeometry", null), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		depthTest,
		color,
		polygonOffset: true,
		polygonOffsetFactor: -10,
		side: 2,
		fog: false
	})), /*#__PURE__*/ import_react.createElement(Line, {
		position: [
			-length / 2,
			-length / 2,
			0
		],
		transparent: true,
		depthTest,
		points,
		lineWidth,
		color,
		opacity,
		polygonOffset: true,
		polygonOffsetFactor: -10,
		userData,
		fog: false,
		renderOrder
	})));
};
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/ScalingSphere.js
var vec1 = /* @__PURE__ */ new Vector3();
var vec2 = /* @__PURE__ */ new Vector3();
var calculateOffset = (clickPoint, normal, rayStart, rayDir) => {
	const e1 = normal.dot(normal);
	const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
	const e3 = normal.dot(rayDir);
	if (e3 === 0) return -e2 / e1;
	vec1.copy(rayDir).multiplyScalar(e1 / e3).sub(normal);
	vec2.copy(rayDir).multiplyScalar(e2 / e3).add(rayStart).sub(clickPoint);
	return -vec1.dot(vec2) / vec1.dot(vec1);
};
var upV = /* @__PURE__ */ new Vector3(0, 1, 0);
var scaleV = /* @__PURE__ */ new Vector3();
var scaleMatrix = /* @__PURE__ */ new Matrix4();
var ScalingSphere = ({ direction, axis }) => {
	const { scaleLimits, annotations, annotationsClass, depthTest, scale, lineWidth, fixed, axisColors, hoveredColor, opacity, renderOrder, onDragStart, onDrag, onDragEnd, userData } = import_react.useContext(context);
	const size = useThree((state) => state.size);
	const camControls = useThree((state) => state.controls);
	const divRef = import_react.useRef(null);
	const objRef = import_react.useRef(null);
	const meshRef = import_react.useRef(null);
	const scale0 = import_react.useRef(1);
	const scaleCur = import_react.useRef(1);
	const clickInfo = import_react.useRef(null);
	const [isHovered, setIsHovered] = import_react.useState(false);
	const position = fixed ? 1.2 : 1.2 * scale;
	const onPointerDown = import_react.useCallback((e) => {
		if (annotations) {
			divRef.current.innerText = `${scaleCur.current.toFixed(2)}`;
			divRef.current.style.display = "block";
		}
		e.stopPropagation();
		const rotation = new Matrix4().extractRotation(objRef.current.matrixWorld);
		const clickPoint = e.point.clone();
		const origin = new Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
		const dir = direction.clone().applyMatrix4(rotation).normalize();
		const mPLG = objRef.current.matrixWorld.clone();
		clickInfo.current = {
			clickPoint,
			dir,
			mPLG,
			mPLGInv: mPLG.clone().invert(),
			offsetMultiplier: fixed ? 1 / calculateScaleFactor(objRef.current.getWorldPosition(vec1), scale, e.camera, size) : 1
		};
		onDragStart({
			component: "Sphere",
			axis,
			origin,
			directions: [dir]
		});
		camControls && (camControls.enabled = false);
		e.target.setPointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		direction,
		onDragStart,
		axis,
		fixed,
		scale,
		size
	]);
	const onPointerMove = import_react.useCallback((e) => {
		e.stopPropagation();
		if (!isHovered) setIsHovered(true);
		if (clickInfo.current) {
			const { clickPoint, dir, mPLG, mPLGInv, offsetMultiplier } = clickInfo.current;
			const [min, max] = (scaleLimits == null ? void 0 : scaleLimits[axis]) || [1e-5, void 0];
			const offsetL = calculateOffset(clickPoint, dir, e.ray.origin, e.ray.direction) * offsetMultiplier;
			const offsetH = fixed ? offsetL : offsetL / scale;
			let upscale = Math.pow(2, offsetH * .2);
			if (e.shiftKey) upscale = Math.round(upscale * 10) / 10;
			upscale = Math.max(upscale, min / scale0.current);
			if (max !== void 0) upscale = Math.min(upscale, max / scale0.current);
			scaleCur.current = scale0.current * upscale;
			meshRef.current.position.set(0, position + offsetL, 0);
			if (annotations) divRef.current.innerText = `${scaleCur.current.toFixed(2)}`;
			scaleV.set(1, 1, 1);
			scaleV.setComponent(axis, upscale);
			scaleMatrix.makeScale(scaleV.x, scaleV.y, scaleV.z).premultiply(mPLG).multiply(mPLGInv);
			onDrag(scaleMatrix);
		}
	}, [
		annotations,
		position,
		onDrag,
		isHovered,
		scaleLimits,
		axis
	]);
	const onPointerUp = import_react.useCallback((e) => {
		if (annotations) divRef.current.style.display = "none";
		e.stopPropagation();
		scale0.current = scaleCur.current;
		clickInfo.current = null;
		meshRef.current.position.set(0, position, 0);
		onDragEnd();
		camControls && (camControls.enabled = true);
		e.target.releasePointerCapture(e.pointerId);
	}, [
		annotations,
		camControls,
		onDragEnd,
		position
	]);
	const onPointerOut = import_react.useCallback((e) => {
		e.stopPropagation();
		setIsHovered(false);
	}, []);
	const { radius, matrixL } = import_react.useMemo(() => {
		const radius = fixed ? lineWidth / scale * 1.8 : scale / 22.5;
		const quaternion = new Quaternion().setFromUnitVectors(upV, direction.clone().normalize());
		return {
			radius,
			matrixL: new Matrix4().makeRotationFromQuaternion(quaternion)
		};
	}, [
		direction,
		scale,
		lineWidth,
		fixed
	]);
	const color = isHovered ? hoveredColor : axisColors[axis];
	return /*#__PURE__*/ import_react.createElement("group", { ref: objRef }, /*#__PURE__*/ import_react.createElement("group", {
		matrix: matrixL,
		matrixAutoUpdate: false,
		onPointerDown,
		onPointerMove,
		onPointerUp,
		onPointerOut
	}, annotations && /*#__PURE__*/ import_react.createElement(Html, { position: [
		0,
		position / 2,
		0
	] }, /*#__PURE__*/ import_react.createElement("div", {
		style: {
			display: "none",
			background: "#151520",
			color: "white",
			padding: "6px 8px",
			borderRadius: 7,
			whiteSpace: "nowrap"
		},
		className: annotationsClass,
		ref: divRef
	})), /*#__PURE__*/ import_react.createElement("mesh", {
		ref: meshRef,
		position: [
			0,
			position,
			0
		],
		renderOrder,
		userData
	}, /*#__PURE__*/ import_react.createElement("sphereGeometry", { args: [
		radius,
		12,
		12
	] }), /*#__PURE__*/ import_react.createElement("meshBasicMaterial", {
		transparent: true,
		depthTest,
		color,
		opacity,
		polygonOffset: true,
		polygonOffsetFactor: -10
	}))));
};
//#endregion
//#region node_modules/@react-three/drei/web/pivotControls/index.js
var mL0 = /* @__PURE__ */ new Matrix4();
var mW0 = /* @__PURE__ */ new Matrix4();
var mP = /* @__PURE__ */ new Matrix4();
var mPInv = /* @__PURE__ */ new Matrix4();
var mW = /* @__PURE__ */ new Matrix4();
var mL = /* @__PURE__ */ new Matrix4();
var mL0Inv = /* @__PURE__ */ new Matrix4();
var mdL = /* @__PURE__ */ new Matrix4();
var mG = /* @__PURE__ */ new Matrix4();
var bb = /* @__PURE__ */ new Box3();
var bbObj = /* @__PURE__ */ new Box3();
var vCenter = /* @__PURE__ */ new Vector3();
var vSize = /* @__PURE__ */ new Vector3();
var vAnchorOffset = /* @__PURE__ */ new Vector3();
var vPosition = /* @__PURE__ */ new Vector3();
var vScale = /* @__PURE__ */ new Vector3();
var xDir = /* @__PURE__ */ new Vector3(1, 0, 0);
var yDir = /* @__PURE__ */ new Vector3(0, 1, 0);
var zDir = /* @__PURE__ */ new Vector3(0, 0, 1);
var PivotControls = /* @__PURE__ */ import_react.forwardRef(({ enabled = true, matrix, onDragStart, onDrag, onDragEnd, autoTransform = true, anchor, disableAxes = false, disableSliders = false, disableRotations = false, disableScaling = false, activeAxes = [
	true,
	true,
	true
], offset = [
	0,
	0,
	0
], rotation = [
	0,
	0,
	0
], scale = 1, lineWidth = 4, fixed = false, translationLimits, rotationLimits, scaleLimits, depthTest = true, renderOrder = 500, axisColors = [
	"#ff2060",
	"#20df80",
	"#2080ff"
], hoveredColor = "#ffff40", annotations = false, annotationsClass, opacity = 1, visible = true, userData, children, ...props }, fRef) => {
	const invalidate = useThree((state) => state.invalidate);
	const parentRef = import_react.useRef(null);
	const ref = import_react.useRef(null);
	const gizmoRef = import_react.useRef(null);
	const childrenRef = import_react.useRef(null);
	const translation = import_react.useRef([
		0,
		0,
		0
	]);
	const cameraScale = import_react.useRef(new Vector3(1, 1, 1));
	const gizmoScale = import_react.useRef(new Vector3(1, 1, 1));
	import_react.useLayoutEffect(() => {
		if (!anchor) return;
		childrenRef.current.updateWorldMatrix(true, true);
		mPInv.copy(childrenRef.current.matrixWorld).invert();
		bb.makeEmpty();
		childrenRef.current.traverse((obj) => {
			if (!obj.geometry) return;
			if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
			mL.copy(obj.matrixWorld).premultiply(mPInv);
			bbObj.copy(obj.geometry.boundingBox);
			bbObj.applyMatrix4(mL);
			bb.union(bbObj);
		});
		vCenter.copy(bb.max).add(bb.min).multiplyScalar(.5);
		vSize.copy(bb.max).sub(bb.min).multiplyScalar(.5);
		vAnchorOffset.copy(vSize).multiply(new Vector3(...anchor)).add(vCenter);
		vPosition.set(...offset).add(vAnchorOffset);
		gizmoRef.current.position.copy(vPosition);
		invalidate();
	});
	const config = import_react.useMemo(() => ({
		onDragStart: (props) => {
			mL0.copy(ref.current.matrix);
			mW0.copy(ref.current.matrixWorld);
			onDragStart && onDragStart(props);
			invalidate();
		},
		onDrag: (mdW) => {
			mP.copy(parentRef.current.matrixWorld);
			mPInv.copy(mP).invert();
			mW.copy(mW0).premultiply(mdW);
			mL.copy(mW).premultiply(mPInv);
			mL0Inv.copy(mL0).invert();
			mdL.copy(mL).multiply(mL0Inv);
			if (autoTransform) ref.current.matrix.copy(mL);
			onDrag && onDrag(mL, mdL, mW, mdW);
			invalidate();
		},
		onDragEnd: () => {
			if (onDragEnd) onDragEnd();
			invalidate();
		},
		translation,
		translationLimits,
		rotationLimits,
		axisColors,
		hoveredColor,
		opacity,
		scale,
		lineWidth,
		fixed,
		depthTest,
		renderOrder,
		userData,
		annotations,
		annotationsClass
	}), [
		onDragStart,
		onDrag,
		onDragEnd,
		translation,
		translationLimits,
		rotationLimits,
		scaleLimits,
		depthTest,
		scale,
		lineWidth,
		fixed,
		...axisColors,
		hoveredColor,
		opacity,
		userData,
		autoTransform,
		annotations,
		annotationsClass
	]);
	const vec = new Vector3();
	useFrame((state) => {
		if (fixed) {
			const sf = calculateScaleFactor(gizmoRef.current.getWorldPosition(vec), scale, state.camera, state.size);
			cameraScale.current.setScalar(sf);
		}
		if (matrix && matrix instanceof Matrix4) ref.current.matrix = matrix;
		ref.current.updateWorldMatrix(true, true);
		mG.makeRotationFromEuler(gizmoRef.current.rotation).setPosition(gizmoRef.current.position).premultiply(ref.current.matrixWorld);
		gizmoScale.current.setFromMatrixScale(mG);
		vScale.copy(cameraScale.current).divide(gizmoScale.current);
		if (Math.abs(gizmoRef.current.scale.x - vScale.x) > 1e-4 || Math.abs(gizmoRef.current.scale.y - vScale.y) > 1e-4 || Math.abs(gizmoRef.current.scale.z - vScale.z) > 1e-4) {
			gizmoRef.current.scale.copy(vScale);
			state.invalidate();
		}
	});
	import_react.useImperativeHandle(fRef, () => ref.current, []);
	return /*#__PURE__*/ import_react.createElement(context.Provider, { value: config }, /*#__PURE__*/ import_react.createElement("group", { ref: parentRef }, /*#__PURE__*/ import_react.createElement("group", _extends$1({
		ref,
		matrix,
		matrixAutoUpdate: false
	}, props), /*#__PURE__*/ import_react.createElement("group", {
		visible,
		ref: gizmoRef,
		position: offset,
		rotation
	}, enabled && /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, !disableAxes && activeAxes[0] && /*#__PURE__*/ import_react.createElement(AxisArrow, {
		axis: 0,
		direction: xDir
	}), !disableAxes && activeAxes[1] && /*#__PURE__*/ import_react.createElement(AxisArrow, {
		axis: 1,
		direction: yDir
	}), !disableAxes && activeAxes[2] && /*#__PURE__*/ import_react.createElement(AxisArrow, {
		axis: 2,
		direction: zDir
	}), !disableSliders && activeAxes[0] && activeAxes[1] && /*#__PURE__*/ import_react.createElement(PlaneSlider, {
		axis: 2,
		dir1: xDir,
		dir2: yDir
	}), !disableSliders && activeAxes[0] && activeAxes[2] && /*#__PURE__*/ import_react.createElement(PlaneSlider, {
		axis: 1,
		dir1: zDir,
		dir2: xDir
	}), !disableSliders && activeAxes[2] && activeAxes[1] && /*#__PURE__*/ import_react.createElement(PlaneSlider, {
		axis: 0,
		dir1: yDir,
		dir2: zDir
	}), !disableRotations && activeAxes[0] && activeAxes[1] && /*#__PURE__*/ import_react.createElement(AxisRotator, {
		axis: 2,
		dir1: xDir,
		dir2: yDir
	}), !disableRotations && activeAxes[0] && activeAxes[2] && /*#__PURE__*/ import_react.createElement(AxisRotator, {
		axis: 1,
		dir1: zDir,
		dir2: xDir
	}), !disableRotations && activeAxes[2] && activeAxes[1] && /*#__PURE__*/ import_react.createElement(AxisRotator, {
		axis: 0,
		dir1: yDir,
		dir2: zDir
	}), !disableScaling && activeAxes[0] && /*#__PURE__*/ import_react.createElement(ScalingSphere, {
		axis: 0,
		direction: xDir
	}), !disableScaling && activeAxes[1] && /*#__PURE__*/ import_react.createElement(ScalingSphere, {
		axis: 1,
		direction: yDir
	}), !disableScaling && activeAxes[2] && /*#__PURE__*/ import_react.createElement(ScalingSphere, {
		axis: 2,
		direction: zDir
	}))), /*#__PURE__*/ import_react.createElement("group", { ref: childrenRef }, children))));
});
//#endregion
//#region node_modules/@react-three/drei/web/ScreenVideoTexture.js
/**
* Create a video texture from [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia)
*/
var ScreenVideoTexture = /* @__PURE__ */ (0, import_react.forwardRef)(({ options = { video: true }, ...props }, fref) => {
	const mediaStream = suspend(() => navigator.mediaDevices.getDisplayMedia(options), []);
	(0, import_react.useEffect)(() => {
		return () => {
			mediaStream?.getTracks().forEach((track) => track.stop());
			clear$1([]);
		};
	}, [mediaStream]);
	return /*#__PURE__*/ import_react.createElement(VideoTexture, _extends$1({ ref: fref }, props, { src: mediaStream }));
});
//#endregion
//#region node_modules/@react-three/drei/web/WebcamVideoTexture.js
/**
* Create a video texture from [`getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
*/
var WebcamVideoTexture = /* @__PURE__ */ (0, import_react.forwardRef)(({ constraints = {
	audio: false,
	video: { facingMode: "user" }
}, ...props }, fref) => {
	const mediaStream = suspend(() => navigator.mediaDevices.getUserMedia(constraints), []);
	(0, import_react.useEffect)(() => {
		return () => {
			mediaStream?.getTracks().forEach((track) => track.stop());
			clear$1([]);
		};
	}, [mediaStream]);
	return /*#__PURE__*/ import_react.createElement(VideoTexture, _extends$1({ ref: fref }, props, { src: mediaStream }));
});
//#endregion
//#region node_modules/@react-three/drei/web/Facemesh.js
var defaultLookAt = /* @__PURE__ */ new Vector3(0, 0, -1);
var normal = /* @__PURE__ */ function() {
	const a = new Vector3();
	const b = new Vector3();
	const c = new Vector3();
	const ab = new Vector3();
	const ac = new Vector3();
	return function(v1, v2, v3, v) {
		a.copy(v1);
		b.copy(v2);
		c.copy(v3);
		ab.copy(b).sub(a);
		ac.copy(c).sub(a);
		return v.crossVectors(ac, ab).normalize();
	};
}();
function mean$1(v1, v2) {
	return v1.clone().add(v2).multiplyScalar(.5);
}
var Facemesh = /* @__PURE__ */ import_react.forwardRef(({ points = FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.faceLandmarks[0], face, facialTransformationMatrix, faceBlendshapes, offset, offsetScalar = 80, width, height, depth = 1, verticalTri = [
	159,
	386,
	152
], origin, eyes = true, eyesAsOrigin = false, debug = false, children, ...props }, fref) => {
	var _meshRef$current3;
	if (face) {
		points = face.keypoints;
		console.warn("Facemesh `face` prop is deprecated: use `points` instead");
	}
	const offsetRef = import_react.useRef(null);
	const scaleRef = import_react.useRef(null);
	const originRef = import_react.useRef(null);
	const outerRef = import_react.useRef(null);
	const meshRef = import_react.useRef(null);
	const eyeRightRef = import_react.useRef(null);
	const eyeLeftRef = import_react.useRef(null);
	const [sightDir] = import_react.useState(() => new Vector3());
	const [transform] = import_react.useState(() => new Object3D());
	const [sightDirQuaternion] = import_react.useState(() => new Quaternion());
	const [_origin] = import_react.useState(() => new Vector3());
	const { invalidate } = useThree();
	import_react.useEffect(() => {
		var _meshRef$current;
		(_meshRef$current = meshRef.current) == null || _meshRef$current.geometry.setIndex(FacemeshDatas.TRIANGULATION);
	}, []);
	const [bboxSize] = import_react.useState(() => new Vector3());
	import_react.useEffect(() => {
		var _meshRef$current2, _outerRef$current;
		const faceGeometry = (_meshRef$current2 = meshRef.current) == null ? void 0 : _meshRef$current2.geometry;
		if (!faceGeometry) return;
		faceGeometry.setFromPoints(points);
		faceGeometry.setDrawRange(0, FacemeshDatas.TRIANGULATION.length);
		if (facialTransformationMatrix) {
			transform.matrix.fromArray(facialTransformationMatrix.data);
			transform.matrix.decompose(transform.position, transform.quaternion, transform.scale);
			transform.rotation.y *= -1;
			transform.rotation.z *= -1;
			sightDirQuaternion.setFromEuler(transform.rotation);
			if (offset) {
				var _offsetRef$current;
				transform.position.y *= -1;
				transform.position.z *= -1;
				(_offsetRef$current = offsetRef.current) == null || _offsetRef$current.position.copy(transform.position.divideScalar(offsetScalar));
			} else {
				var _offsetRef$current2;
				(_offsetRef$current2 = offsetRef.current) == null || _offsetRef$current2.position.set(0, 0, 0);
			}
		} else {
			normal(points[verticalTri[0]], points[verticalTri[1]], points[verticalTri[2]], sightDir);
			sightDirQuaternion.setFromUnitVectors(defaultLookAt, sightDir);
		}
		const sightDirQuaternionInverse = sightDirQuaternion.clone().invert();
		faceGeometry.computeBoundingBox();
		if (debug) invalidate();
		faceGeometry.center();
		faceGeometry.applyQuaternion(sightDirQuaternionInverse);
		(_outerRef$current = outerRef.current) == null || _outerRef$current.setRotationFromQuaternion(sightDirQuaternion);
		if (eyes) {
			if (!faceBlendshapes) console.warn("Facemesh `eyes` option only works if `faceBlendshapes` is provided: skipping.");
			else if (eyeRightRef.current && eyeLeftRef.current && originRef.current) if (eyesAsOrigin) {
				const eyeRightSphere = eyeRightRef.current._computeSphere(faceGeometry);
				const eyeLeftSphere = eyeLeftRef.current._computeSphere(faceGeometry);
				origin = mean$1(eyeRightSphere.center, eyeLeftSphere.center).negate();
				eyeRightRef.current._update(faceGeometry, faceBlendshapes, eyeRightSphere);
				eyeLeftRef.current._update(faceGeometry, faceBlendshapes, eyeLeftSphere);
			} else {
				eyeRightRef.current._update(faceGeometry, faceBlendshapes);
				eyeLeftRef.current._update(faceGeometry, faceBlendshapes);
			}
		}
		if (originRef.current) {
			if (origin !== void 0) {
				if (typeof origin === "number") {
					const position = faceGeometry.getAttribute("position");
					_origin.set(-position.getX(origin), -position.getY(origin), -position.getZ(origin));
				} else if (origin.isVector3) _origin.copy(origin);
			} else _origin.setScalar(0);
			originRef.current.position.copy(_origin);
		}
		if (scaleRef.current) {
			let scale = 1;
			if (width || height || depth) {
				faceGeometry.boundingBox.getSize(bboxSize);
				if (width) scale = width / bboxSize.x;
				if (height) scale = height / bboxSize.y;
				if (depth) scale = depth / bboxSize.z;
			}
			scaleRef.current.scale.setScalar(scale !== 1 ? scale : 1);
		}
		faceGeometry.computeVertexNormals();
		faceGeometry.attributes.position.needsUpdate = true;
	}, [
		points,
		facialTransformationMatrix,
		faceBlendshapes,
		transform,
		offset,
		offsetScalar,
		width,
		height,
		depth,
		verticalTri,
		origin,
		eyes,
		debug,
		invalidate,
		sightDir,
		sightDirQuaternion,
		bboxSize,
		_origin
	]);
	const api = import_react.useMemo(() => ({
		outerRef,
		meshRef,
		eyeRightRef,
		eyeLeftRef
	}), []);
	import_react.useImperativeHandle(fref, () => api, [api]);
	const [meshBboxSize] = import_react.useState(() => new Vector3());
	const bbox = (_meshRef$current3 = meshRef.current) == null ? void 0 : _meshRef$current3.geometry.boundingBox;
	const one = (bbox == null ? void 0 : bbox.getSize(meshBboxSize).z) || 1;
	return /*#__PURE__*/ import_react.createElement("group", props, /*#__PURE__*/ import_react.createElement("group", { ref: offsetRef }, /*#__PURE__*/ import_react.createElement("group", { ref: outerRef }, /*#__PURE__*/ import_react.createElement("group", { ref: scaleRef }, debug ? /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, /*#__PURE__*/ import_react.createElement("axesHelper", { args: [one] }), /*#__PURE__*/ import_react.createElement(Line, {
		points: [[
			0,
			0,
			0
		], [
			0,
			0,
			-one
		]],
		color: 65535
	})) : null, /*#__PURE__*/ import_react.createElement("group", { ref: originRef }, eyes && faceBlendshapes && /*#__PURE__*/ import_react.createElement("group", { name: "eyes" }, /*#__PURE__*/ import_react.createElement(FacemeshEye, {
		side: "left",
		ref: eyeRightRef,
		debug
	}), /*#__PURE__*/ import_react.createElement(FacemeshEye, {
		side: "right",
		ref: eyeLeftRef,
		debug
	})), /*#__PURE__*/ import_react.createElement("mesh", {
		ref: meshRef,
		name: "face"
	}, children, debug ? /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, bbox && /*#__PURE__*/ import_react.createElement("box3Helper", { args: [bbox] })) : null))))));
});
var FacemeshEyeDefaults = {
	contourLandmarks: {
		right: [
			33,
			133,
			159,
			145,
			153
		],
		left: [
			263,
			362,
			386,
			374,
			380
		]
	},
	blendshapes: {
		right: [
			14,
			16,
			18,
			12
		],
		left: [
			13,
			15,
			17,
			11
		]
	},
	color: {
		right: "red",
		left: "#00ff00"
	},
	fov: {
		horizontal: 100,
		vertical: 90
	}
};
var FacemeshEye = /* @__PURE__ */ import_react.forwardRef(({ side, debug = true }, fref) => {
	const eyeMeshRef = import_react.useRef(null);
	const irisDirRef = import_react.useRef(null);
	const [sphere] = import_react.useState(() => new Sphere$1());
	const _computeSphere = import_react.useCallback((faceGeometry) => {
		const position = faceGeometry.getAttribute("position");
		const eyeContourPoints = FacemeshEyeDefaults.contourLandmarks[side].map((i) => new Vector3(position.getX(i), position.getY(i), position.getZ(i)));
		sphere.center.set(0, 0, 0);
		eyeContourPoints.forEach((v) => sphere.center.add(v));
		sphere.center.divideScalar(eyeContourPoints.length);
		sphere.radius = eyeContourPoints[0].sub(eyeContourPoints[1]).length() / 2;
		return sphere;
	}, [sphere, side]);
	const [rotation] = import_react.useState(() => new Euler());
	const _update = import_react.useCallback((faceGeometry, faceBlendshapes, sphere) => {
		if (eyeMeshRef.current) {
			var _sphere;
			(_sphere = sphere) !== null && _sphere !== void 0 || (sphere = _computeSphere(faceGeometry));
			eyeMeshRef.current.position.copy(sphere.center);
			eyeMeshRef.current.scale.setScalar(sphere.radius);
		}
		if (faceBlendshapes && irisDirRef.current) {
			const blendshapes = FacemeshEyeDefaults.blendshapes[side];
			const lookIn = faceBlendshapes.categories[blendshapes[0]].score;
			const lookOut = faceBlendshapes.categories[blendshapes[1]].score;
			const lookUp = faceBlendshapes.categories[blendshapes[2]].score;
			const lookDown = faceBlendshapes.categories[blendshapes[3]].score;
			const hfov = FacemeshEyeDefaults.fov.horizontal * MathUtils.DEG2RAD;
			const vfov = FacemeshEyeDefaults.fov.vertical * MathUtils.DEG2RAD;
			const rx = hfov * .5 * (lookDown - lookUp);
			const ry = vfov * .5 * (lookIn - lookOut) * (side === "left" ? 1 : -1);
			rotation.set(rx, ry, 0);
			irisDirRef.current.setRotationFromEuler(rotation);
		}
	}, [
		_computeSphere,
		side,
		rotation
	]);
	const api = import_react.useMemo(() => ({
		eyeMeshRef,
		irisDirRef,
		_computeSphere,
		_update
	}), [_computeSphere, _update]);
	import_react.useImperativeHandle(fref, () => api, [api]);
	const color = FacemeshEyeDefaults.color[side];
	return /*#__PURE__*/ import_react.createElement("group", null, /*#__PURE__*/ import_react.createElement("group", { ref: eyeMeshRef }, debug && /*#__PURE__*/ import_react.createElement("axesHelper", null), /*#__PURE__*/ import_react.createElement("group", { ref: irisDirRef }, /*#__PURE__*/ import_react.createElement(import_react.Fragment, null, debug && /*#__PURE__*/ import_react.createElement(Line, {
		points: [[
			0,
			0,
			0
		], [
			0,
			0,
			-2
		]],
		lineWidth: 1,
		color
	})))));
});
var FacemeshDatas = {
	TRIANGULATION: [
		127,
		34,
		139,
		11,
		0,
		37,
		232,
		231,
		120,
		72,
		37,
		39,
		128,
		121,
		47,
		232,
		121,
		128,
		104,
		69,
		67,
		175,
		171,
		148,
		157,
		154,
		155,
		118,
		50,
		101,
		73,
		39,
		40,
		9,
		151,
		108,
		48,
		115,
		131,
		194,
		204,
		211,
		74,
		40,
		185,
		80,
		42,
		183,
		40,
		92,
		186,
		230,
		229,
		118,
		202,
		212,
		214,
		83,
		18,
		17,
		76,
		61,
		146,
		160,
		29,
		30,
		56,
		157,
		173,
		106,
		204,
		194,
		135,
		214,
		192,
		203,
		165,
		98,
		21,
		71,
		68,
		51,
		45,
		4,
		144,
		24,
		23,
		77,
		146,
		91,
		205,
		50,
		187,
		201,
		200,
		18,
		91,
		106,
		182,
		90,
		91,
		181,
		85,
		84,
		17,
		206,
		203,
		36,
		148,
		171,
		140,
		92,
		40,
		39,
		193,
		189,
		244,
		159,
		158,
		28,
		247,
		246,
		161,
		236,
		3,
		196,
		54,
		68,
		104,
		193,
		168,
		8,
		117,
		228,
		31,
		189,
		193,
		55,
		98,
		97,
		99,
		126,
		47,
		100,
		166,
		79,
		218,
		155,
		154,
		26,
		209,
		49,
		131,
		135,
		136,
		150,
		47,
		126,
		217,
		223,
		52,
		53,
		45,
		51,
		134,
		211,
		170,
		140,
		67,
		69,
		108,
		43,
		106,
		91,
		230,
		119,
		120,
		226,
		130,
		247,
		63,
		53,
		52,
		238,
		20,
		242,
		46,
		70,
		156,
		78,
		62,
		96,
		46,
		53,
		63,
		143,
		34,
		227,
		173,
		155,
		133,
		123,
		117,
		111,
		44,
		125,
		19,
		236,
		134,
		51,
		216,
		206,
		205,
		154,
		153,
		22,
		39,
		37,
		167,
		200,
		201,
		208,
		36,
		142,
		100,
		57,
		212,
		202,
		20,
		60,
		99,
		28,
		158,
		157,
		35,
		226,
		113,
		160,
		159,
		27,
		204,
		202,
		210,
		113,
		225,
		46,
		43,
		202,
		204,
		62,
		76,
		77,
		137,
		123,
		116,
		41,
		38,
		72,
		203,
		129,
		142,
		64,
		98,
		240,
		49,
		102,
		64,
		41,
		73,
		74,
		212,
		216,
		207,
		42,
		74,
		184,
		169,
		170,
		211,
		170,
		149,
		176,
		105,
		66,
		69,
		122,
		6,
		168,
		123,
		147,
		187,
		96,
		77,
		90,
		65,
		55,
		107,
		89,
		90,
		180,
		101,
		100,
		120,
		63,
		105,
		104,
		93,
		137,
		227,
		15,
		86,
		85,
		129,
		102,
		49,
		14,
		87,
		86,
		55,
		8,
		9,
		100,
		47,
		121,
		145,
		23,
		22,
		88,
		89,
		179,
		6,
		122,
		196,
		88,
		95,
		96,
		138,
		172,
		136,
		215,
		58,
		172,
		115,
		48,
		219,
		42,
		80,
		81,
		195,
		3,
		51,
		43,
		146,
		61,
		171,
		175,
		199,
		81,
		82,
		38,
		53,
		46,
		225,
		144,
		163,
		110,
		246,
		33,
		7,
		52,
		65,
		66,
		229,
		228,
		117,
		34,
		127,
		234,
		107,
		108,
		69,
		109,
		108,
		151,
		48,
		64,
		235,
		62,
		78,
		191,
		129,
		209,
		126,
		111,
		35,
		143,
		163,
		161,
		246,
		117,
		123,
		50,
		222,
		65,
		52,
		19,
		125,
		141,
		221,
		55,
		65,
		3,
		195,
		197,
		25,
		7,
		33,
		220,
		237,
		44,
		70,
		71,
		139,
		122,
		193,
		245,
		247,
		130,
		33,
		71,
		21,
		162,
		153,
		158,
		159,
		170,
		169,
		150,
		188,
		174,
		196,
		216,
		186,
		92,
		144,
		160,
		161,
		2,
		97,
		167,
		141,
		125,
		241,
		164,
		167,
		37,
		72,
		38,
		12,
		145,
		159,
		160,
		38,
		82,
		13,
		63,
		68,
		71,
		226,
		35,
		111,
		158,
		153,
		154,
		101,
		50,
		205,
		206,
		92,
		165,
		209,
		198,
		217,
		165,
		167,
		97,
		220,
		115,
		218,
		133,
		112,
		243,
		239,
		238,
		241,
		214,
		135,
		169,
		190,
		173,
		133,
		171,
		208,
		32,
		125,
		44,
		237,
		86,
		87,
		178,
		85,
		86,
		179,
		84,
		85,
		180,
		83,
		84,
		181,
		201,
		83,
		182,
		137,
		93,
		132,
		76,
		62,
		183,
		61,
		76,
		184,
		57,
		61,
		185,
		212,
		57,
		186,
		214,
		207,
		187,
		34,
		143,
		156,
		79,
		239,
		237,
		123,
		137,
		177,
		44,
		1,
		4,
		201,
		194,
		32,
		64,
		102,
		129,
		213,
		215,
		138,
		59,
		166,
		219,
		242,
		99,
		97,
		2,
		94,
		141,
		75,
		59,
		235,
		24,
		110,
		228,
		25,
		130,
		226,
		23,
		24,
		229,
		22,
		23,
		230,
		26,
		22,
		231,
		112,
		26,
		232,
		189,
		190,
		243,
		221,
		56,
		190,
		28,
		56,
		221,
		27,
		28,
		222,
		29,
		27,
		223,
		30,
		29,
		224,
		247,
		30,
		225,
		238,
		79,
		20,
		166,
		59,
		75,
		60,
		75,
		240,
		147,
		177,
		215,
		20,
		79,
		166,
		187,
		147,
		213,
		112,
		233,
		244,
		233,
		128,
		245,
		128,
		114,
		188,
		114,
		217,
		174,
		131,
		115,
		220,
		217,
		198,
		236,
		198,
		131,
		134,
		177,
		132,
		58,
		143,
		35,
		124,
		110,
		163,
		7,
		228,
		110,
		25,
		356,
		389,
		368,
		11,
		302,
		267,
		452,
		350,
		349,
		302,
		303,
		269,
		357,
		343,
		277,
		452,
		453,
		357,
		333,
		332,
		297,
		175,
		152,
		377,
		384,
		398,
		382,
		347,
		348,
		330,
		303,
		304,
		270,
		9,
		336,
		337,
		278,
		279,
		360,
		418,
		262,
		431,
		304,
		408,
		409,
		310,
		415,
		407,
		270,
		409,
		410,
		450,
		348,
		347,
		422,
		430,
		434,
		313,
		314,
		17,
		306,
		307,
		375,
		387,
		388,
		260,
		286,
		414,
		398,
		335,
		406,
		418,
		364,
		367,
		416,
		423,
		358,
		327,
		251,
		284,
		298,
		281,
		5,
		4,
		373,
		374,
		253,
		307,
		320,
		321,
		425,
		427,
		411,
		421,
		313,
		18,
		321,
		405,
		406,
		320,
		404,
		405,
		315,
		16,
		17,
		426,
		425,
		266,
		377,
		400,
		369,
		322,
		391,
		269,
		417,
		465,
		464,
		386,
		257,
		258,
		466,
		260,
		388,
		456,
		399,
		419,
		284,
		332,
		333,
		417,
		285,
		8,
		346,
		340,
		261,
		413,
		441,
		285,
		327,
		460,
		328,
		355,
		371,
		329,
		392,
		439,
		438,
		382,
		341,
		256,
		429,
		420,
		360,
		364,
		394,
		379,
		277,
		343,
		437,
		443,
		444,
		283,
		275,
		440,
		363,
		431,
		262,
		369,
		297,
		338,
		337,
		273,
		375,
		321,
		450,
		451,
		349,
		446,
		342,
		467,
		293,
		334,
		282,
		458,
		461,
		462,
		276,
		353,
		383,
		308,
		324,
		325,
		276,
		300,
		293,
		372,
		345,
		447,
		382,
		398,
		362,
		352,
		345,
		340,
		274,
		1,
		19,
		456,
		248,
		281,
		436,
		427,
		425,
		381,
		256,
		252,
		269,
		391,
		393,
		200,
		199,
		428,
		266,
		330,
		329,
		287,
		273,
		422,
		250,
		462,
		328,
		258,
		286,
		384,
		265,
		353,
		342,
		387,
		259,
		257,
		424,
		431,
		430,
		342,
		353,
		276,
		273,
		335,
		424,
		292,
		325,
		307,
		366,
		447,
		345,
		271,
		303,
		302,
		423,
		266,
		371,
		294,
		455,
		460,
		279,
		278,
		294,
		271,
		272,
		304,
		432,
		434,
		427,
		272,
		407,
		408,
		394,
		430,
		431,
		395,
		369,
		400,
		334,
		333,
		299,
		351,
		417,
		168,
		352,
		280,
		411,
		325,
		319,
		320,
		295,
		296,
		336,
		319,
		403,
		404,
		330,
		348,
		349,
		293,
		298,
		333,
		323,
		454,
		447,
		15,
		16,
		315,
		358,
		429,
		279,
		14,
		15,
		316,
		285,
		336,
		9,
		329,
		349,
		350,
		374,
		380,
		252,
		318,
		402,
		403,
		6,
		197,
		419,
		318,
		319,
		325,
		367,
		364,
		365,
		435,
		367,
		397,
		344,
		438,
		439,
		272,
		271,
		311,
		195,
		5,
		281,
		273,
		287,
		291,
		396,
		428,
		199,
		311,
		271,
		268,
		283,
		444,
		445,
		373,
		254,
		339,
		263,
		466,
		249,
		282,
		334,
		296,
		449,
		347,
		346,
		264,
		447,
		454,
		336,
		296,
		299,
		338,
		10,
		151,
		278,
		439,
		455,
		292,
		407,
		415,
		358,
		371,
		355,
		340,
		345,
		372,
		390,
		249,
		466,
		346,
		347,
		280,
		442,
		443,
		282,
		19,
		94,
		370,
		441,
		442,
		295,
		248,
		419,
		197,
		263,
		255,
		359,
		440,
		275,
		274,
		300,
		383,
		368,
		351,
		412,
		465,
		263,
		467,
		466,
		301,
		368,
		389,
		380,
		374,
		386,
		395,
		378,
		379,
		412,
		351,
		419,
		436,
		426,
		322,
		373,
		390,
		388,
		2,
		164,
		393,
		370,
		462,
		461,
		164,
		0,
		267,
		302,
		11,
		12,
		374,
		373,
		387,
		268,
		12,
		13,
		293,
		300,
		301,
		446,
		261,
		340,
		385,
		384,
		381,
		330,
		266,
		425,
		426,
		423,
		391,
		429,
		355,
		437,
		391,
		327,
		326,
		440,
		457,
		438,
		341,
		382,
		362,
		459,
		457,
		461,
		434,
		430,
		394,
		414,
		463,
		362,
		396,
		369,
		262,
		354,
		461,
		457,
		316,
		403,
		402,
		315,
		404,
		403,
		314,
		405,
		404,
		313,
		406,
		405,
		421,
		418,
		406,
		366,
		401,
		361,
		306,
		408,
		407,
		291,
		409,
		408,
		287,
		410,
		409,
		432,
		436,
		410,
		434,
		416,
		411,
		264,
		368,
		383,
		309,
		438,
		457,
		352,
		376,
		401,
		274,
		275,
		4,
		421,
		428,
		262,
		294,
		327,
		358,
		433,
		416,
		367,
		289,
		455,
		439,
		462,
		370,
		326,
		2,
		326,
		370,
		305,
		460,
		455,
		254,
		449,
		448,
		255,
		261,
		446,
		253,
		450,
		449,
		252,
		451,
		450,
		256,
		452,
		451,
		341,
		453,
		452,
		413,
		464,
		463,
		441,
		413,
		414,
		258,
		442,
		441,
		257,
		443,
		442,
		259,
		444,
		443,
		260,
		445,
		444,
		467,
		342,
		445,
		459,
		458,
		250,
		289,
		392,
		290,
		290,
		328,
		460,
		376,
		433,
		435,
		250,
		290,
		392,
		411,
		416,
		433,
		341,
		463,
		464,
		453,
		464,
		465,
		357,
		465,
		412,
		343,
		412,
		399,
		360,
		363,
		440,
		437,
		399,
		456,
		420,
		456,
		363,
		401,
		435,
		288,
		372,
		383,
		353,
		339,
		255,
		249,
		448,
		261,
		255,
		133,
		243,
		190,
		133,
		155,
		112,
		33,
		246,
		247,
		33,
		130,
		25,
		398,
		384,
		286,
		362,
		398,
		414,
		362,
		463,
		341,
		263,
		359,
		467,
		263,
		249,
		255,
		466,
		467,
		260,
		75,
		60,
		166,
		238,
		239,
		79,
		162,
		127,
		139,
		72,
		11,
		37,
		121,
		232,
		120,
		73,
		72,
		39,
		114,
		128,
		47,
		233,
		232,
		128,
		103,
		104,
		67,
		152,
		175,
		148,
		173,
		157,
		155,
		119,
		118,
		101,
		74,
		73,
		40,
		107,
		9,
		108,
		49,
		48,
		131,
		32,
		194,
		211,
		184,
		74,
		185,
		191,
		80,
		183,
		185,
		40,
		186,
		119,
		230,
		118,
		210,
		202,
		214,
		84,
		83,
		17,
		77,
		76,
		146,
		161,
		160,
		30,
		190,
		56,
		173,
		182,
		106,
		194,
		138,
		135,
		192,
		129,
		203,
		98,
		54,
		21,
		68,
		5,
		51,
		4,
		145,
		144,
		23,
		90,
		77,
		91,
		207,
		205,
		187,
		83,
		201,
		18,
		181,
		91,
		182,
		180,
		90,
		181,
		16,
		85,
		17,
		205,
		206,
		36,
		176,
		148,
		140,
		165,
		92,
		39,
		245,
		193,
		244,
		27,
		159,
		28,
		30,
		247,
		161,
		174,
		236,
		196,
		103,
		54,
		104,
		55,
		193,
		8,
		111,
		117,
		31,
		221,
		189,
		55,
		240,
		98,
		99,
		142,
		126,
		100,
		219,
		166,
		218,
		112,
		155,
		26,
		198,
		209,
		131,
		169,
		135,
		150,
		114,
		47,
		217,
		224,
		223,
		53,
		220,
		45,
		134,
		32,
		211,
		140,
		109,
		67,
		108,
		146,
		43,
		91,
		231,
		230,
		120,
		113,
		226,
		247,
		105,
		63,
		52,
		241,
		238,
		242,
		124,
		46,
		156,
		95,
		78,
		96,
		70,
		46,
		63,
		116,
		143,
		227,
		116,
		123,
		111,
		1,
		44,
		19,
		3,
		236,
		51,
		207,
		216,
		205,
		26,
		154,
		22,
		165,
		39,
		167,
		199,
		200,
		208,
		101,
		36,
		100,
		43,
		57,
		202,
		242,
		20,
		99,
		56,
		28,
		157,
		124,
		35,
		113,
		29,
		160,
		27,
		211,
		204,
		210,
		124,
		113,
		46,
		106,
		43,
		204,
		96,
		62,
		77,
		227,
		137,
		116,
		73,
		41,
		72,
		36,
		203,
		142,
		235,
		64,
		240,
		48,
		49,
		64,
		42,
		41,
		74,
		214,
		212,
		207,
		183,
		42,
		184,
		210,
		169,
		211,
		140,
		170,
		176,
		104,
		105,
		69,
		193,
		122,
		168,
		50,
		123,
		187,
		89,
		96,
		90,
		66,
		65,
		107,
		179,
		89,
		180,
		119,
		101,
		120,
		68,
		63,
		104,
		234,
		93,
		227,
		16,
		15,
		85,
		209,
		129,
		49,
		15,
		14,
		86,
		107,
		55,
		9,
		120,
		100,
		121,
		153,
		145,
		22,
		178,
		88,
		179,
		197,
		6,
		196,
		89,
		88,
		96,
		135,
		138,
		136,
		138,
		215,
		172,
		218,
		115,
		219,
		41,
		42,
		81,
		5,
		195,
		51,
		57,
		43,
		61,
		208,
		171,
		199,
		41,
		81,
		38,
		224,
		53,
		225,
		24,
		144,
		110,
		105,
		52,
		66,
		118,
		229,
		117,
		227,
		34,
		234,
		66,
		107,
		69,
		10,
		109,
		151,
		219,
		48,
		235,
		183,
		62,
		191,
		142,
		129,
		126,
		116,
		111,
		143,
		7,
		163,
		246,
		118,
		117,
		50,
		223,
		222,
		52,
		94,
		19,
		141,
		222,
		221,
		65,
		196,
		3,
		197,
		45,
		220,
		44,
		156,
		70,
		139,
		188,
		122,
		245,
		139,
		71,
		162,
		145,
		153,
		159,
		149,
		170,
		150,
		122,
		188,
		196,
		206,
		216,
		92,
		163,
		144,
		161,
		164,
		2,
		167,
		242,
		141,
		241,
		0,
		164,
		37,
		11,
		72,
		12,
		144,
		145,
		160,
		12,
		38,
		13,
		70,
		63,
		71,
		31,
		226,
		111,
		157,
		158,
		154,
		36,
		101,
		205,
		203,
		206,
		165,
		126,
		209,
		217,
		98,
		165,
		97,
		237,
		220,
		218,
		237,
		239,
		241,
		210,
		214,
		169,
		140,
		171,
		32,
		241,
		125,
		237,
		179,
		86,
		178,
		180,
		85,
		179,
		181,
		84,
		180,
		182,
		83,
		181,
		194,
		201,
		182,
		177,
		137,
		132,
		184,
		76,
		183,
		185,
		61,
		184,
		186,
		57,
		185,
		216,
		212,
		186,
		192,
		214,
		187,
		139,
		34,
		156,
		218,
		79,
		237,
		147,
		123,
		177,
		45,
		44,
		4,
		208,
		201,
		32,
		98,
		64,
		129,
		192,
		213,
		138,
		235,
		59,
		219,
		141,
		242,
		97,
		97,
		2,
		141,
		240,
		75,
		235,
		229,
		24,
		228,
		31,
		25,
		226,
		230,
		23,
		229,
		231,
		22,
		230,
		232,
		26,
		231,
		233,
		112,
		232,
		244,
		189,
		243,
		189,
		221,
		190,
		222,
		28,
		221,
		223,
		27,
		222,
		224,
		29,
		223,
		225,
		30,
		224,
		113,
		247,
		225,
		99,
		60,
		240,
		213,
		147,
		215,
		60,
		20,
		166,
		192,
		187,
		213,
		243,
		112,
		244,
		244,
		233,
		245,
		245,
		128,
		188,
		188,
		114,
		174,
		134,
		131,
		220,
		174,
		217,
		236,
		236,
		198,
		134,
		215,
		177,
		58,
		156,
		143,
		124,
		25,
		110,
		7,
		31,
		228,
		25,
		264,
		356,
		368,
		0,
		11,
		267,
		451,
		452,
		349,
		267,
		302,
		269,
		350,
		357,
		277,
		350,
		452,
		357,
		299,
		333,
		297,
		396,
		175,
		377,
		381,
		384,
		382,
		280,
		347,
		330,
		269,
		303,
		270,
		151,
		9,
		337,
		344,
		278,
		360,
		424,
		418,
		431,
		270,
		304,
		409,
		272,
		310,
		407,
		322,
		270,
		410,
		449,
		450,
		347,
		432,
		422,
		434,
		18,
		313,
		17,
		291,
		306,
		375,
		259,
		387,
		260,
		424,
		335,
		418,
		434,
		364,
		416,
		391,
		423,
		327,
		301,
		251,
		298,
		275,
		281,
		4,
		254,
		373,
		253,
		375,
		307,
		321,
		280,
		425,
		411,
		200,
		421,
		18,
		335,
		321,
		406,
		321,
		320,
		405,
		314,
		315,
		17,
		423,
		426,
		266,
		396,
		377,
		369,
		270,
		322,
		269,
		413,
		417,
		464,
		385,
		386,
		258,
		248,
		456,
		419,
		298,
		284,
		333,
		168,
		417,
		8,
		448,
		346,
		261,
		417,
		413,
		285,
		326,
		327,
		328,
		277,
		355,
		329,
		309,
		392,
		438,
		381,
		382,
		256,
		279,
		429,
		360,
		365,
		364,
		379,
		355,
		277,
		437,
		282,
		443,
		283,
		281,
		275,
		363,
		395,
		431,
		369,
		299,
		297,
		337,
		335,
		273,
		321,
		348,
		450,
		349,
		359,
		446,
		467,
		283,
		293,
		282,
		250,
		458,
		462,
		300,
		276,
		383,
		292,
		308,
		325,
		283,
		276,
		293,
		264,
		372,
		447,
		346,
		352,
		340,
		354,
		274,
		19,
		363,
		456,
		281,
		426,
		436,
		425,
		380,
		381,
		252,
		267,
		269,
		393,
		421,
		200,
		428,
		371,
		266,
		329,
		432,
		287,
		422,
		290,
		250,
		328,
		385,
		258,
		384,
		446,
		265,
		342,
		386,
		387,
		257,
		422,
		424,
		430,
		445,
		342,
		276,
		422,
		273,
		424,
		306,
		292,
		307,
		352,
		366,
		345,
		268,
		271,
		302,
		358,
		423,
		371,
		327,
		294,
		460,
		331,
		279,
		294,
		303,
		271,
		304,
		436,
		432,
		427,
		304,
		272,
		408,
		395,
		394,
		431,
		378,
		395,
		400,
		296,
		334,
		299,
		6,
		351,
		168,
		376,
		352,
		411,
		307,
		325,
		320,
		285,
		295,
		336,
		320,
		319,
		404,
		329,
		330,
		349,
		334,
		293,
		333,
		366,
		323,
		447,
		316,
		15,
		315,
		331,
		358,
		279,
		317,
		14,
		316,
		8,
		285,
		9,
		277,
		329,
		350,
		253,
		374,
		252,
		319,
		318,
		403,
		351,
		6,
		419,
		324,
		318,
		325,
		397,
		367,
		365,
		288,
		435,
		397,
		278,
		344,
		439,
		310,
		272,
		311,
		248,
		195,
		281,
		375,
		273,
		291,
		175,
		396,
		199,
		312,
		311,
		268,
		276,
		283,
		445,
		390,
		373,
		339,
		295,
		282,
		296,
		448,
		449,
		346,
		356,
		264,
		454,
		337,
		336,
		299,
		337,
		338,
		151,
		294,
		278,
		455,
		308,
		292,
		415,
		429,
		358,
		355,
		265,
		340,
		372,
		388,
		390,
		466,
		352,
		346,
		280,
		295,
		442,
		282,
		354,
		19,
		370,
		285,
		441,
		295,
		195,
		248,
		197,
		457,
		440,
		274,
		301,
		300,
		368,
		417,
		351,
		465,
		251,
		301,
		389,
		385,
		380,
		386,
		394,
		395,
		379,
		399,
		412,
		419,
		410,
		436,
		322,
		387,
		373,
		388,
		326,
		2,
		393,
		354,
		370,
		461,
		393,
		164,
		267,
		268,
		302,
		12,
		386,
		374,
		387,
		312,
		268,
		13,
		298,
		293,
		301,
		265,
		446,
		340,
		380,
		385,
		381,
		280,
		330,
		425,
		322,
		426,
		391,
		420,
		429,
		437,
		393,
		391,
		326,
		344,
		440,
		438,
		458,
		459,
		461,
		364,
		434,
		394,
		428,
		396,
		262,
		274,
		354,
		457,
		317,
		316,
		402,
		316,
		315,
		403,
		315,
		314,
		404,
		314,
		313,
		405,
		313,
		421,
		406,
		323,
		366,
		361,
		292,
		306,
		407,
		306,
		291,
		408,
		291,
		287,
		409,
		287,
		432,
		410,
		427,
		434,
		411,
		372,
		264,
		383,
		459,
		309,
		457,
		366,
		352,
		401,
		1,
		274,
		4,
		418,
		421,
		262,
		331,
		294,
		358,
		435,
		433,
		367,
		392,
		289,
		439,
		328,
		462,
		326,
		94,
		2,
		370,
		289,
		305,
		455,
		339,
		254,
		448,
		359,
		255,
		446,
		254,
		253,
		449,
		253,
		252,
		450,
		252,
		256,
		451,
		256,
		341,
		452,
		414,
		413,
		463,
		286,
		441,
		414,
		286,
		258,
		441,
		258,
		257,
		442,
		257,
		259,
		443,
		259,
		260,
		444,
		260,
		467,
		445,
		309,
		459,
		250,
		305,
		289,
		290,
		305,
		290,
		460,
		401,
		376,
		435,
		309,
		250,
		392,
		376,
		411,
		433,
		453,
		341,
		464,
		357,
		453,
		465,
		343,
		357,
		412,
		437,
		343,
		399,
		344,
		360,
		440,
		420,
		437,
		456,
		360,
		420,
		363,
		361,
		401,
		288,
		265,
		372,
		353,
		390,
		339,
		249,
		339,
		448,
		255
	],
	SAMPLE_FACE: {
		"keypoints": [
			{
				"x": 356.2804412841797,
				"y": 295.1960563659668,
				"z": -23.786449432373047,
				"name": "lips"
			},
			{
				"x": 354.8859405517578,
				"y": 264.69520568847656,
				"z": -36.718435287475586
			},
			{
				"x": 355.2180862426758,
				"y": 275.3360366821289,
				"z": -21.183712482452393
			},
			{
				"x": 347.349853515625,
				"y": 242.4400234222412,
				"z": -25.093655586242676
			},
			{
				"x": 354.40135955810547,
				"y": 256.67933464050293,
				"z": -38.23572635650635
			},
			{
				"x": 353.7689971923828,
				"y": 247.54886627197266,
				"z": -34.5475435256958
			},
			{
				"x": 352.1288299560547,
				"y": 227.34312057495117,
				"z": -13.095386028289795
			},
			{
				"x": 303.5013198852539,
				"y": 234.67002868652344,
				"z": 12.500141859054565,
				"name": "rightEye"
			},
			{
				"x": 351.09378814697266,
				"y": 211.87547206878662,
				"z": -6.413471698760986
			},
			{
				"x": 350.7115936279297,
				"y": 202.1251630783081,
				"z": -6.413471698760986
			},
			{
				"x": 348.33667755126953,
				"y": 168.7741756439209,
				"z": 6.483500003814697,
				"name": "faceOval"
			},
			{
				"x": 356.4806365966797,
				"y": 299.2995357513428,
				"z": -23.144519329071045
			},
			{
				"x": 356.5511703491211,
				"y": 302.66146659851074,
				"z": -21.020312309265137
			},
			{
				"x": 356.6239547729492,
				"y": 304.1536331176758,
				"z": -18.137459754943848,
				"name": "lips"
			},
			{
				"x": 356.5807342529297,
				"y": 305.1840591430664,
				"z": -18.767719268798828,
				"name": "lips"
			},
			{
				"x": 356.8241500854492,
				"y": 308.25711250305176,
				"z": -20.16829490661621
			},
			{
				"x": 357.113037109375,
				"y": 312.26277351379395,
				"z": -22.10575819015503
			},
			{
				"x": 357.34962463378906,
				"y": 317.1123218536377,
				"z": -21.837315559387207,
				"name": "lips"
			},
			{
				"x": 357.6658630371094,
				"y": 325.51036834716797,
				"z": -16.27002477645874
			},
			{
				"x": 355.0201416015625,
				"y": 269.36279296875,
				"z": -33.73054027557373
			},
			{
				"x": 348.5237503051758,
				"y": 270.33411026000977,
				"z": -24.93025302886963
			},
			{
				"x": 279.97331619262695,
				"y": 213.24176788330078,
				"z": 47.759642601013184,
				"name": "faceOval"
			},
			{
				"x": 322.66529083251953,
				"y": 238.5027265548706,
				"z": 5.535193085670471
			},
			{
				"x": 316.0983657836914,
				"y": 239.94489669799805,
				"z": 5.777376294136047
			},
			{
				"x": 309.9431610107422,
				"y": 240.24518966674805,
				"z": 7.510589361190796
			},
			{
				"x": 301.31994247436523,
				"y": 237.86138534545898,
				"z": 13.118728399276733
			},
			{
				"x": 328.14266204833984,
				"y": 235.80496788024902,
				"z": 6.646900177001953
			},
			{
				"x": 313.7326431274414,
				"y": 222.11161136627197,
				"z": 3.9887237548828125
			},
			{
				"x": 320.45196533203125,
				"y": 221.87729358673096,
				"z": 4.601476192474365
			},
			{
				"x": 307.35679626464844,
				"y": 223.63793849945068,
				"z": 5.932023525238037
			},
			{
				"x": 303.0031204223633,
				"y": 226.3743782043457,
				"z": 8.479321002960205
			},
			{
				"x": 296.80023193359375,
				"y": 242.94299125671387,
				"z": 15.931552648544312
			},
			{
				"x": 332.2352981567383,
				"y": 340.77341079711914,
				"z": -10.165848731994629
			},
			{
				"x": 301.38587951660156,
				"y": 233.46447944641113,
				"z": 14.764405488967896,
				"name": "rightEye"
			},
			{
				"x": 279.0147018432617,
				"y": 244.37155723571777,
				"z": 45.77549457550049
			},
			{
				"x": 289.60548400878906,
				"y": 239.1807460784912,
				"z": 23.191204071044922
			},
			{
				"x": 320.32257080078125,
				"y": 267.1292781829834,
				"z": -4.954537749290466
			},
			{
				"x": 347.64583587646484,
				"y": 294.4955062866211,
				"z": -23.062820434570312,
				"name": "lips"
			},
			{
				"x": 349.28138732910156,
				"y": 303.1095886230469,
				"z": -20.238323211669922
			},
			{
				"x": 338.9453125,
				"y": 298.19186210632324,
				"z": -19.456336498260498,
				"name": "lips"
			},
			{
				"x": 333.36788177490234,
				"y": 302.6706790924072,
				"z": -14.776077270507812,
				"name": "lips"
			},
			{
				"x": 342.89188385009766,
				"y": 304.3561363220215,
				"z": -17.752301692962646
			},
			{
				"x": 337.7375030517578,
				"y": 306.0098361968994,
				"z": -13.410515785217285
			},
			{
				"x": 325.6159210205078,
				"y": 316.22995376586914,
				"z": -6.681914925575256
			},
			{
				"x": 349.0104675292969,
				"y": 264.9818515777588,
				"z": -36.274919509887695
			},
			{
				"x": 347.7138900756836,
				"y": 257.5664806365967,
				"z": -37.67549514770508
			},
			{
				"x": 291.79357528686523,
				"y": 218.88171672821045,
				"z": 11.578094959259033,
				"name": "rightEyebrow"
			},
			{
				"x": 332.2689437866211,
				"y": 247.56946563720703,
				"z": -3.3730539679527283
			},
			{
				"x": 332.0074462890625,
				"y": 267.1201229095459,
				"z": -19.969879388809204
			},
			{
				"x": 331.27952575683594,
				"y": 263.6967658996582,
				"z": -17.47218608856201
			},
			{
				"x": 301.04373931884766,
				"y": 269.56552505493164,
				"z": 3.61815482378006
			},
			{
				"x": 347.4863815307617,
				"y": 249.0706443786621,
				"z": -32.633421421051025
			},
			{
				"x": 307.26118087768555,
				"y": 208.2646894454956,
				"z": 1.1591226607561111,
				"name": "rightEyebrow"
			},
			{
				"x": 297.91919708251953,
				"y": 212.22604751586914,
				"z": 5.914516448974609,
				"name": "rightEyebrow"
			},
			{
				"x": 285.1651382446289,
				"y": 197.98450469970703,
				"z": 36.391637325286865,
				"name": "faceOval"
			},
			{
				"x": 337.04097747802734,
				"y": 211.25229835510254,
				"z": -4.548954665660858
			},
			{
				"x": 326.5912628173828,
				"y": 223.16698551177979,
				"z": 6.670243740081787
			},
			{
				"x": 320.05664825439453,
				"y": 309.5834255218506,
				"z": -4.055835008621216
			},
			{
				"x": 289.6866226196289,
				"y": 314.617395401001,
				"z": 53.875489234924316,
				"name": "faceOval"
			},
			{
				"x": 337.4256896972656,
				"y": 270.8755302429199,
				"z": -17.67060160636902
			},
			{
				"x": 343.69922637939453,
				"y": 273.0000400543213,
				"z": -18.756048679351807
			},
			{
				"x": 327.4242401123047,
				"y": 309.22399520874023,
				"z": -4.703601002693176,
				"name": "lips"
			},
			{
				"x": 330.37220001220703,
				"y": 308.3323001861572,
				"z": -6.442649960517883
			},
			{
				"x": 293.87027740478516,
				"y": 207.7961826324463,
				"z": 9.821539521217346,
				"name": "rightEyebrow"
			},
			{
				"x": 332.11437225341797,
				"y": 271.22812271118164,
				"z": -16.64351224899292
			},
			{
				"x": 320.1197814941406,
				"y": 207.40366458892822,
				"z": -2.48164564371109,
				"name": "rightEyebrow"
			},
			{
				"x": 318.59575271606445,
				"y": 201.07443809509277,
				"z": -3.110446035861969,
				"name": "rightEyebrow"
			},
			{
				"x": 310.72303771972656,
				"y": 175.75075149536133,
				"z": 13.328815698623657,
				"name": "faceOval"
			},
			{
				"x": 289.67578887939453,
				"y": 202.29835510253906,
				"z": 21.370456218719482
			},
			{
				"x": 315.30879974365234,
				"y": 187.35260009765625,
				"z": 5.0304025411605835
			},
			{
				"x": 287.8936767578125,
				"y": 216.54793739318848,
				"z": 17.81065821647644,
				"name": "rightEyebrow"
			},
			{
				"x": 283.9391899108887,
				"y": 215.01142501831055,
				"z": 32.04984903335571
			},
			{
				"x": 348.35330963134766,
				"y": 299.4155788421631,
				"z": -22.47924566268921
			},
			{
				"x": 341.1790466308594,
				"y": 301.8221855163574,
				"z": -18.977805376052856
			},
			{
				"x": 335.69713592529297,
				"y": 304.4266891479492,
				"z": -14.682706594467163
			},
			{
				"x": 339.4615173339844,
				"y": 272.3654365539551,
				"z": -16.38674020767212
			},
			{
				"x": 328.99600982666016,
				"y": 308.86685371398926,
				"z": -5.616893768310547
			},
			{
				"x": 332.00313568115234,
				"y": 309.1875743865967,
				"z": -10.335084199905396
			},
			{
				"x": 331.0068130493164,
				"y": 307.9274368286133,
				"z": -6.681914925575256,
				"name": "lips"
			},
			{
				"x": 341.13792419433594,
				"y": 266.4876937866211,
				"z": -26.56425952911377
			},
			{
				"x": 339.02950286865234,
				"y": 305.6663703918457,
				"z": -12.33674168586731,
				"name": "lips"
			},
			{
				"x": 344.22935485839844,
				"y": 304.9452781677246,
				"z": -15.161235332489014,
				"name": "lips"
			},
			{
				"x": 350.1844024658203,
				"y": 304.374303817749,
				"z": -17.5305438041687,
				"name": "lips"
			},
			{
				"x": 348.52630615234375,
				"y": 325.9562301635742,
				"z": -16.164982318878174
			},
			{
				"x": 348.6581802368164,
				"y": 317.1624183654785,
				"z": -21.510512828826904,
				"name": "lips"
			},
			{
				"x": 348.9766311645508,
				"y": 312.1923065185547,
				"z": -21.708929538726807
			},
			{
				"x": 349.2427444458008,
				"y": 308.0660820007324,
				"z": -19.643079042434692
			},
			{
				"x": 349.67491149902344,
				"y": 305.42747497558594,
				"z": -18.16080331802368,
				"name": "lips"
			},
			{
				"x": 337.95589447021484,
				"y": 306.6535949707031,
				"z": -12.803598642349243,
				"name": "lips"
			},
			{
				"x": 337.06878662109375,
				"y": 307.63169288635254,
				"z": -14.274203777313232
			},
			{
				"x": 335.77449798583984,
				"y": 309.8449516296387,
				"z": -15.698124170303345
			},
			{
				"x": 334.6099090576172,
				"y": 312.7997016906738,
				"z": -14.764405488967896,
				"name": "lips"
			},
			{
				"x": 327.2330856323242,
				"y": 293.80866050720215,
				"z": -11.864047050476074
			},
			{
				"x": 280.97679138183594,
				"y": 279.79928970336914,
				"z": 68.90834331512451,
				"name": "faceOval"
			},
			{
				"x": 355.13843536376953,
				"y": 271.7875671386719,
				"z": -25.350427627563477
			},
			{
				"x": 334.7235870361328,
				"y": 307.4656391143799,
				"z": -9.302158951759338,
				"name": "lips"
			},
			{
				"x": 333.5293960571289,
				"y": 307.89782524108887,
				"z": -10.200862884521484
			},
			{
				"x": 346.29688262939453,
				"y": 276.4256286621094,
				"z": -19.748122692108154
			},
			{
				"x": 335.16246795654297,
				"y": 276.22097969055176,
				"z": -12.313398122787476
			},
			{
				"x": 345.09132385253906,
				"y": 274.7082996368408,
				"z": -19.304605722427368
			},
			{
				"x": 325.4267883300781,
				"y": 252.95130729675293,
				"z": -1.6661019623279572
			},
			{
				"x": 315.347843170166,
				"y": 259.05200958251953,
				"z": -.25604281574487686
			},
			{
				"x": 330.44933319091797,
				"y": 267.7570152282715,
				"z": -14.017432928085327
			},
			{
				"x": 294.96768951416016,
				"y": 185.26001930236816,
				"z": 23.903164863586426,
				"name": "faceOval"
			},
			{
				"x": 299.63531494140625,
				"y": 192.7913761138916,
				"z": 12.640198469161987
			},
			{
				"x": 304.5452117919922,
				"y": 202.4142837524414,
				"z": 3.244667649269104,
				"name": "rightEyebrow"
			},
			{
				"x": 331.6915512084961,
				"y": 320.0467872619629,
				"z": -10.632705688476562
			},
			{
				"x": 334.5911407470703,
				"y": 201.27566814422607,
				"z": -6.133356094360352,
				"name": "rightEyebrow"
			},
			{
				"x": 331.4815902709961,
				"y": 185.44180870056152,
				"z": .6627205014228821
			},
			{
				"x": 328.05816650390625,
				"y": 170.8385467529297,
				"z": 7.358860373497009,
				"name": "faceOval"
			},
			{
				"x": 304.49764251708984,
				"y": 239.76297855377197,
				"z": 10.387605428695679
			},
			{
				"x": 290.6382179260254,
				"y": 248.85257720947266,
				"z": 19.03616428375244
			},
			{
				"x": 331.5682601928711,
				"y": 233.20727348327637,
				"z": 7.837390303611755
			},
			{
				"x": 295.5115509033203,
				"y": 228.9834451675415,
				"z": 14.41426157951355
			},
			{
				"x": 336.94332122802734,
				"y": 241.8259334564209,
				"z": -5.27842104434967
			},
			{
				"x": 336.2792205810547,
				"y": 262.7049922943115,
				"z": -26.12074375152588
			},
			{
				"x": 284.4102478027344,
				"y": 255.3262710571289,
				"z": 25.467140674591064
			},
			{
				"x": 295.1420593261719,
				"y": 253.02655220031738,
				"z": 12.430112361907959
			},
			{
				"x": 303.5196113586426,
				"y": 254.20703887939453,
				"z": 6.139191389083862
			},
			{
				"x": 315.73450088500977,
				"y": 251.64799690246582,
				"z": 3.3788898587226868
			},
			{
				"x": 324.69661712646484,
				"y": 247.56494522094727,
				"z": 2.3328344523906708
			},
			{
				"x": 331.57970428466797,
				"y": 243.02241325378418,
				"z": 1.1423448473215103
			},
			{
				"x": 345.6210708618164,
				"y": 229.9976634979248,
				"z": -10.825285911560059
			},
			{
				"x": 286.26644134521484,
				"y": 270.37991523742676,
				"z": 21.708929538726807
			},
			{
				"x": 290.2525520324707,
				"y": 228.4921360015869,
				"z": 17.71728754043579
			},
			{
				"x": 351.65367126464844,
				"y": 269.3400764465332,
				"z": -33.450424671173096
			},
			{
				"x": 333.1378936767578,
				"y": 253.88388633728027,
				"z": -7.230473756790161
			},
			{
				"x": 277.8318977355957,
				"y": 246.95331573486328,
				"z": 68.20805549621582,
				"name": "faceOval"
			},
			{
				"x": 336.6680908203125,
				"y": 238.10003757476807,
				"z": .7688578963279724
			},
			{
				"x": 329.95800018310547,
				"y": 269.18323516845703,
				"z": -7.207130789756775
			},
			{
				"x": 299.17491912841797,
				"y": 234.13324356079102,
				"z": 15.95489501953125
			},
			{
				"x": 335.61729431152344,
				"y": 258.71752738952637,
				"z": -23.016133308410645
			},
			{
				"x": 284.1079330444336,
				"y": 297.0343494415283,
				"z": 63.25934886932373,
				"name": "faceOval"
			},
			{
				"x": 331.44542694091797,
				"y": 230.6892442703247,
				"z": 9.92658257484436,
				"name": "rightEye"
			},
			{
				"x": 341.41536712646484,
				"y": 253.01264762878418,
				"z": -29.038610458374023
			},
			{
				"x": 303.5472869873047,
				"y": 327.5896739959717,
				"z": 16.725212335586548
			},
			{
				"x": 304.7756576538086,
				"y": 337.4389457702637,
				"z": 27.38126277923584,
				"name": "faceOval"
			},
			{
				"x": 280.80501556396484,
				"y": 275.32050132751465,
				"z": 45.0752067565918
			},
			{
				"x": 295.43582916259766,
				"y": 318.4501647949219,
				"z": 26.2608003616333
			},
			{
				"x": 281.4303207397461,
				"y": 228.7355661392212,
				"z": 40.94350814819336
			},
			{
				"x": 331.2549591064453,
				"y": 349.4216537475586,
				"z": -7.376367449760437
			},
			{
				"x": 352.4247741699219,
				"y": 271.7330074310303,
				"z": -24.953596591949463
			},
			{
				"x": 327.5672912597656,
				"y": 260.41900634765625,
				"z": -5.456410646438599
			},
			{
				"x": 284.5432472229004,
				"y": 241.7647933959961,
				"z": 29.668869972229004
			},
			{
				"x": 310,
				"y": 235.66174507141113,
				"z": 8.502663969993591,
				"name": "rightEye"
			},
			{
				"x": 315.7071113586426,
				"y": 235.7572603225708,
				"z": 6.938687562942505,
				"name": "rightEye"
			},
			{
				"x": 330.41088104248047,
				"y": 311.04143142700195,
				"z": -9.325502514839172,
				"name": "lips"
			},
			{
				"x": 288.5377502441406,
				"y": 285.31983375549316,
				"z": 21.837315559387207
			},
			{
				"x": 344.55039978027344,
				"y": 359.4300842285156,
				"z": -6.705257892608643,
				"name": "faceOval"
			},
			{
				"x": 323.41880798339844,
				"y": 351.67362213134766,
				"z": 7.802375555038452,
				"name": "faceOval"
			},
			{
				"x": 314.64088439941406,
				"y": 346.11894607543945,
				"z": 16.36339783668518,
				"name": "faceOval"
			},
			{
				"x": 349.4945526123047,
				"y": 184.8434829711914,
				"z": -.21847527474164963
			},
			{
				"x": 359.24694061279297,
				"y": 359.8348903656006,
				"z": -8.403456211090088,
				"name": "faceOval"
			},
			{
				"x": 321.26182556152344,
				"y": 234.64492321014404,
				"z": 6.90950870513916,
				"name": "rightEye"
			},
			{
				"x": 326.318359375,
				"y": 232.90250301361084,
				"z": 8.029969334602356,
				"name": "rightEye"
			},
			{
				"x": 329.6211624145508,
				"y": 231.6195774078369,
				"z": 9.722331762313843,
				"name": "rightEye"
			},
			{
				"x": 285.9398078918457,
				"y": 228.2351303100586,
				"z": 24.650139808654785
			},
			{
				"x": 325.79288482666016,
				"y": 227.88007736206055,
				"z": 7.469738721847534,
				"name": "rightEye"
			},
			{
				"x": 320.1699447631836,
				"y": 227.5934886932373,
				"z": 6.168370842933655,
				"name": "rightEye"
			},
			{
				"x": 314.85408782958984,
				"y": 227.85282611846924,
				"z": 6.2675780057907104,
				"name": "rightEye"
			},
			{
				"x": 309.3084907531738,
				"y": 229.1516876220703,
				"z": 7.7031683921813965,
				"name": "rightEye"
			},
			{
				"x": 305.5621337890625,
				"y": 230.92366218566895,
				"z": 9.722331762313843,
				"name": "rightEye"
			},
			{
				"x": 277.8681945800781,
				"y": 228.5354232788086,
				"z": 59.71122741699219,
				"name": "faceOval"
			},
			{
				"x": 306.1444664001465,
				"y": 235.1954698562622,
				"z": 10.603528022766113,
				"name": "rightEye"
			},
			{
				"x": 355.4478454589844,
				"y": 281.96210861206055,
				"z": -20.565123558044434
			},
			{
				"x": 333.02661895751953,
				"y": 288.0105400085449,
				"z": -14.72939133644104
			},
			{
				"x": 337.15728759765625,
				"y": 269.2059516906738,
				"z": -19.8414945602417
			},
			{
				"x": 345.9898376464844,
				"y": 283.5453128814697,
				"z": -20.4834246635437
			},
			{
				"x": 351.48963928222656,
				"y": 219.98916149139404,
				"z": -7.0378947257995605
			},
			{
				"x": 312.39574432373047,
				"y": 336.50628089904785,
				"z": 8.671900033950806
			},
			{
				"x": 321.32152557373047,
				"y": 343.1755256652832,
				"z": .9067271649837494
			},
			{
				"x": 343.78379821777344,
				"y": 353.2975959777832,
				"z": -14.355905055999756
			},
			{
				"x": 296.8791389465332,
				"y": 327.91497230529785,
				"z": 41.01353645324707,
				"name": "faceOval"
			},
			{
				"x": 329.6939468383789,
				"y": 229.27897453308105,
				"z": 8.934508562088013,
				"name": "rightEye"
			},
			{
				"x": 341.6905212402344,
				"y": 241.4073657989502,
				"z": -14.589333534240723
			},
			{
				"x": 359.03079986572266,
				"y": 353.48859786987305,
				"z": -15.803166627883911
			},
			{
				"x": 333.1861877441406,
				"y": 356.43213272094727,
				"z": -1.0234417766332626,
				"name": "faceOval"
			},
			{
				"x": 283.97483825683594,
				"y": 291.4318656921387,
				"z": 41.94725513458252
			},
			{
				"x": 343.33770751953125,
				"y": 305.830135345459,
				"z": -15.756480693817139,
				"name": "lips"
			},
			{
				"x": 342.40283966064453,
				"y": 307.7453899383545,
				"z": -17.4021577835083
			},
			{
				"x": 341.53621673583984,
				"y": 311.0595703125,
				"z": -19.047834873199463
			},
			{
				"x": 340.9107208251953,
				"y": 315.4837703704834,
				"z": -18.5576331615448,
				"name": "lips"
			},
			{
				"x": 339.1478729248047,
				"y": 323.42233657836914,
				"z": -14.367576837539673
			},
			{
				"x": 333.3201599121094,
				"y": 307.4406337738037,
				"z": -9.617288708686829
			},
			{
				"x": 331.2411117553711,
				"y": 306.9811820983887,
				"z": -9.669809937477112
			},
			{
				"x": 329.23255920410156,
				"y": 306.0508346557617,
				"z": -9.582273960113525,
				"name": "lips"
			},
			{
				"x": 322.4586486816406,
				"y": 301.33323669433594,
				"z": -7.720675468444824
			},
			{
				"x": 297.1712112426758,
				"y": 286.9552803039551,
				"z": 8.240055441856384
			},
			{
				"x": 341.3060760498047,
				"y": 235.4432201385498,
				"z": -7.504753470420837
			},
			{
				"x": 336.9318389892578,
				"y": 224.3451976776123,
				"z": 5.829898118972778
			},
			{
				"x": 332.65323638916016,
				"y": 226.70403957366943,
				"z": 8.105834126472473
			},
			{
				"x": 334.67357635498047,
				"y": 306.4397621154785,
				"z": -8.981193900108337,
				"name": "lips"
			},
			{
				"x": 297.4601936340332,
				"y": 306.29210472106934,
				"z": 15.476365089416504
			},
			{
				"x": 342.9119110107422,
				"y": 222.37077713012695,
				"z": -2.754466235637665
			},
			{
				"x": 335.4629898071289,
				"y": 332.20250129699707,
				"z": -11.823196411132812
			},
			{
				"x": 353.2412338256836,
				"y": 240.56339263916016,
				"z": -27.147831916809082
			},
			{
				"x": 346.3080596923828,
				"y": 236.41446590423584,
				"z": -18.452589511871338
			},
			{
				"x": 352.6475143432617,
				"y": 234.1420555114746,
				"z": -19.748122692108154
			},
			{
				"x": 337.3209762573242,
				"y": 253.39937210083008,
				"z": -16.024924516677856
			},
			{
				"x": 358.6122131347656,
				"y": 344.90861892700195,
				"z": -18.592647314071655
			},
			{
				"x": 358.1117248535156,
				"y": 334.64990615844727,
				"z": -17.49552845954895
			},
			{
				"x": 346.4450454711914,
				"y": 335.0321102142334,
				"z": -16.32838249206543
			},
			{
				"x": 319.17640686035156,
				"y": 320.2833938598633,
				"z": -3.276764452457428
			},
			{
				"x": 325.2540588378906,
				"y": 276.2369728088379,
				"z": -6.460157036781311
			},
			{
				"x": 326.7214584350586,
				"y": 327.3939514160156,
				"z": -7.417217493057251
			},
			{
				"x": 310.7190132141113,
				"y": 277.2265148162842,
				"z": -3.5452082753181458
			},
			{
				"x": 319.78355407714844,
				"y": 284.8238182067871,
				"z": -6.4543211460113525
			},
			{
				"x": 305.773983001709,
				"y": 290.83580017089844,
				"z": .06907138042151928
			},
			{
				"x": 344.4001770019531,
				"y": 344.85408782958984,
				"z": -16.946970224380493
			},
			{
				"x": 333.1879425048828,
				"y": 258.74256134033203,
				"z": -11.90489649772644
			},
			{
				"x": 313.80598068237305,
				"y": 327.08919525146484,
				"z": 2.2277912497520447
			},
			{
				"x": 322.9637908935547,
				"y": 334.6819496154785,
				"z": -3.3643004298210144
			},
			{
				"x": 313.4055519104004,
				"y": 311.2166690826416,
				"z": -1.1175429821014404
			},
			{
				"x": 291.0865783691406,
				"y": 298.2831001281738,
				"z": 22.467575073242188
			},
			{
				"x": 305.6580924987793,
				"y": 313.3707904815674,
				"z": 5.561453700065613
			},
			{
				"x": 288.23760986328125,
				"y": 305.9941864013672,
				"z": 36.765122413635254
			},
			{
				"x": 315.10692596435547,
				"y": 296.26991271972656,
				"z": -4.604393839836121
			},
			{
				"x": 337.50518798828125,
				"y": 247.5944423675537,
				"z": -10.597691535949707
			},
			{
				"x": 338.8450622558594,
				"y": 265.47778129577637,
				"z": -27.778091430664062
			},
			{
				"x": 334.25254821777344,
				"y": 269.0671920776367,
				"z": -20.938611030578613
			},
			{
				"x": 341.64512634277344,
				"y": 259.6387195587158,
				"z": -32.189905643463135
			},
			{
				"x": 331.44081115722656,
				"y": 219.0976095199585,
				"z": 4.207563698291779
			},
			{
				"x": 320.56339263916016,
				"y": 216.49658203125,
				"z": 2.930997312068939
			},
			{
				"x": 311.21912002563477,
				"y": 216.57853603363037,
				"z": 2.9674705862998962
			},
			{
				"x": 303.46256256103516,
				"y": 218.54614734649658,
				"z": 5.357203483581543
			},
			{
				"x": 297.99999237060547,
				"y": 222.505202293396,
				"z": 9.325502514839172
			},
			{
				"x": 294.93839263916016,
				"y": 236.39654159545898,
				"z": 18.534289598464966
			},
			{
				"x": 278.87489318847656,
				"y": 259.7095584869385,
				"z": 45.68212032318115
			},
			{
				"x": 300.3782653808594,
				"y": 245.38593292236328,
				"z": 12.278382778167725
			},
			{
				"x": 307.06348419189453,
				"y": 246.36857986450195,
				"z": 8.164191246032715
			},
			{
				"x": 315.5229187011719,
				"y": 245.3949737548828,
				"z": 5.503097176551819
			},
			{
				"x": 323.71395111083984,
				"y": 242.75178909301758,
				"z": 4.6335723996162415
			},
			{
				"x": 330.2785873413086,
				"y": 239.34658527374268,
				"z": 4.937030673027039
			},
			{
				"x": 334.6982192993164,
				"y": 236.0460376739502,
				"z": 4.823233783245087
			},
			{
				"x": 279.3412208557129,
				"y": 263.5196113586426,
				"z": 70.91583728790283,
				"name": "faceOval"
			},
			{
				"x": 334.65972900390625,
				"y": 271.6648578643799,
				"z": -17.775644063949585
			},
			{
				"x": 342.05677032470703,
				"y": 246.99846267700195,
				"z": -20.84523916244507
			},
			{
				"x": 344.0357971191406,
				"y": 264.5701503753662,
				"z": -32.936880588531494
			},
			{
				"x": 348.25531005859375,
				"y": 268.6645030975342,
				"z": -30.695960521697998
			},
			{
				"x": 344.12227630615234,
				"y": 266.34212493896484,
				"z": -29.808926582336426
			},
			{
				"x": 337.12318420410156,
				"y": 274.2556858062744,
				"z": -15.768152475357056
			},
			{
				"x": 349.49047088623047,
				"y": 269.071683883667,
				"z": -32.51670837402344
			},
			{
				"x": 350.1683044433594,
				"y": 271.4691352844238,
				"z": -24.93025302886963
			},
			{
				"x": 333.9634704589844,
				"y": 230.56639194488525,
				"z": 8.89949381351471
			},
			{
				"x": 338.2147979736328,
				"y": 231.4807891845703,
				"z": 4.6715047955513
			},
			{
				"x": 340.4712677001953,
				"y": 231.74463272094727,
				"z": -.34996166825294495
			},
			{
				"x": 303.28975677490234,
				"y": 232.24980354309082,
				"z": 11.916568279266357,
				"name": "rightEye"
			},
			{
				"x": 299.4649124145508,
				"y": 229.53842639923096,
				"z": 12.325069904327393
			},
			{
				"x": 359.09618377685547,
				"y": 241.77349090576172,
				"z": -24.650139808654785
			},
			{
				"x": 399.46216583251953,
				"y": 229.89503860473633,
				"z": 15.919880867004395,
				"name": "leftEye"
			},
			{
				"x": 361.38919830322266,
				"y": 269.6129894256592,
				"z": -24.510080814361572
			},
			{
				"x": 416.9973373413086,
				"y": 206.0895538330078,
				"z": 53.26857566833496,
				"name": "faceOval"
			},
			{
				"x": 381.32179260253906,
				"y": 235.5476474761963,
				"z": 7.6214683055877686
			},
			{
				"x": 387.8068542480469,
				"y": 236.25958442687988,
				"z": 8.345099091529846
			},
			{
				"x": 393.95751953125,
				"y": 235.8660364151001,
				"z": 10.475142002105713
			},
			{
				"x": 401.84600830078125,
				"y": 232.77019500732422,
				"z": 16.760226488113403
			},
			{
				"x": 375.70568084716797,
				"y": 233.48456382751465,
				"z": 8.234220147132874
			},
			{
				"x": 388.17752838134766,
				"y": 218.94717693328857,
				"z": 6.810300946235657
			},
			{
				"x": 381.64928436279297,
				"y": 219.2656660079956,
				"z": 6.711093783378601
			},
			{
				"x": 394.4760513305664,
				"y": 219.66821193695068,
				"z": 9.173773527145386
			},
			{
				"x": 398.8843536376953,
				"y": 221.8837022781372,
				"z": 12.03328251838684
			},
			{
				"x": 406.5454864501953,
				"y": 237.12156772613525,
				"z": 19.7131085395813
			},
			{
				"x": 383.87447357177734,
				"y": 337.6932907104492,
				"z": -8.631049990653992
			},
			{
				"x": 401.2682342529297,
				"y": 228.5916566848755,
				"z": 18.359217643737793,
				"name": "leftEye"
			},
			{
				"x": 422.0449447631836,
				"y": 236.73934936523438,
				"z": 51.16771221160889
			},
			{
				"x": 412.69153594970703,
				"y": 232.80198097229004,
				"z": 27.52131938934326
			},
			{
				"x": 387.3497772216797,
				"y": 263.298397064209,
				"z": -2.8609684109687805
			},
			{
				"x": 364.5124053955078,
				"y": 293.39221000671387,
				"z": -22.397546768188477,
				"name": "lips"
			},
			{
				"x": 363.62987518310547,
				"y": 302.1291446685791,
				"z": -19.643079042434692
			},
			{
				"x": 373.2334518432617,
				"y": 295.8647060394287,
				"z": -18.125789165496826,
				"name": "lips"
			},
			{
				"x": 378.83365631103516,
				"y": 299.5177745819092,
				"z": -13.153743743896484,
				"name": "lips"
			},
			{
				"x": 369.91477966308594,
				"y": 302.5704002380371,
				"z": -16.65518283843994
			},
			{
				"x": 374.9167251586914,
				"y": 303.5416603088379,
				"z": -11.963253021240234
			},
			{
				"x": 387.58888244628906,
				"y": 312.2716999053955,
				"z": -4.680258631706238
			},
			{
				"x": 360.6635284423828,
				"y": 264.31986808776855,
				"z": -35.94811677932739
			},
			{
				"x": 361.04564666748047,
				"y": 256.8225860595703,
				"z": -37.278664112091064
			},
			{
				"x": 408.3855438232422,
				"y": 213.52088928222656,
				"z": 15.756480693817139,
				"name": "leftEyebrow"
			},
			{
				"x": 373.2946014404297,
				"y": 245.38101196289062,
				"z": -1.9316278398036957
			},
			{
				"x": 376.83860778808594,
				"y": 264.3721103668213,
				"z": -18.510947227478027
			},
			{
				"x": 376.9546127319336,
				"y": 261.0010528564453,
				"z": -15.989909172058105
			},
			{
				"x": 406.1498260498047,
				"y": 263.5030174255371,
				"z": 7.072908878326416
			},
			{
				"x": 360.07205963134766,
				"y": 248.3631706237793,
				"z": -32.16656446456909
			},
			{
				"x": 393.11119079589844,
				"y": 205.10473251342773,
				"z": 3.7786373496055603,
				"name": "leftEyebrow"
			},
			{
				"x": 402.12791442871094,
				"y": 207.89000988006592,
				"z": 9.383859634399414,
				"name": "leftEyebrow"
			},
			{
				"x": 410.8693313598633,
				"y": 191.6182279586792,
				"z": 41.27030849456787,
				"name": "faceOval"
			},
			{
				"x": 364.9509811401367,
				"y": 210.40483474731445,
				"z": -3.758212625980377
			},
			{
				"x": 375.94444274902344,
				"y": 221.1331844329834,
				"z": 8.368442058563232
			},
			{
				"x": 392.1904754638672,
				"y": 305.0360298156738,
				"z": -1.752179116010666
			},
			{
				"x": 419.50225830078125,
				"y": 307.25592613220215,
				"z": 58.96425247192383,
				"name": "faceOval"
			},
			{
				"x": 372.0027160644531,
				"y": 268.7212657928467,
				"z": -16.631840467453003
			},
			{
				"x": 366.1614227294922,
				"y": 271.6237449645996,
				"z": -18.219159841537476
			},
			{
				"x": 385.00938415527344,
				"y": 305.3863334655762,
				"z": -2.567722797393799
			},
			{
				"x": 381.99771881103516,
				"y": 304.9723720550537,
				"z": -4.575215280056
			},
			{
				"x": 405.078125,
				"y": 203.21216583251953,
				"z": 13.713973760604858,
				"name": "leftEyebrow"
			},
			{
				"x": 377.13207244873047,
				"y": 268.4710121154785,
				"z": -15.266278982162476
			},
			{
				"x": 380.9713363647461,
				"y": 205.36980628967285,
				"z": -.7250899076461792,
				"name": "leftEyebrow"
			},
			{
				"x": 381.7788314819336,
				"y": 198.9268398284912,
				"z": -1.184653863310814,
				"name": "leftEyebrow"
			},
			{
				"x": 385.5204772949219,
				"y": 172.1484375,
				"z": 16.04826807975769,
				"name": "faceOval"
			},
			{
				"x": 407.94189453125,
				"y": 196.76236152648926,
				"z": 25.723915100097656
			},
			{
				"x": 383.03890228271484,
				"y": 184.5157527923584,
				"z": 7.393874526023865
			},
			{
				"x": 411.61781311035156,
				"y": 210.79241752624512,
				"z": 22.315845489501953,
				"name": "leftEyebrow"
			},
			{
				"x": 414.30870056152344,
				"y": 208.4643030166626,
				"z": 37.021894454956055
			},
			{
				"x": 364.28722381591797,
				"y": 298.35777282714844,
				"z": -21.86065673828125
			},
			{
				"x": 371.3682556152344,
				"y": 299.78848457336426,
				"z": -17.834001779556274
			},
			{
				"x": 376.88201904296875,
				"y": 301.6696071624756,
				"z": -13.153743743896484
			},
			{
				"x": 370.2193832397461,
				"y": 270.49095153808594,
				"z": -15.569736957550049
			},
			{
				"x": 383.5081100463867,
				"y": 305.2726364135742,
				"z": -3.673594295978546
			},
			{
				"x": 380.73760986328125,
				"y": 305.96869468688965,
				"z": -8.660228252410889
			},
			{
				"x": 381.2334442138672,
				"y": 304.63574409484863,
				"z": -4.820316135883331,
				"name": "lips"
			},
			{
				"x": 368.1698989868164,
				"y": 264.8884963989258,
				"z": -25.653886795043945
			},
			{
				"x": 373.5087203979492,
				"y": 303.4233856201172,
				"z": -10.95950722694397,
				"name": "lips"
			},
			{
				"x": 368.4544372558594,
				"y": 303.29601287841797,
				"z": -14.169161319732666,
				"name": "lips"
			},
			{
				"x": 362.76554107666016,
				"y": 303.5735607147217,
				"z": -16.911956071853638,
				"name": "lips"
			},
			{
				"x": 366.60980224609375,
				"y": 324.8870658874512,
				"z": -15.616422891616821
			},
			{
				"x": 365.7067108154297,
				"y": 315.95678329467773,
				"z": -20.903596878051758,
				"name": "lips"
			},
			{
				"x": 365.0083923339844,
				"y": 311.2232208251953,
				"z": -21.066999435424805
			},
			{
				"x": 364.1508102416992,
				"y": 307.0583438873291,
				"z": -18.907777070999146
			},
			{
				"x": 363.37512969970703,
				"y": 304.5721435546875,
				"z": -17.42550015449524,
				"name": "lips"
			},
			{
				"x": 374.580078125,
				"y": 304.3059539794922,
				"z": -11.40302300453186,
				"name": "lips"
			},
			{
				"x": 375.55362701416016,
				"y": 305.0998020172119,
				"z": -12.861957550048828
			},
			{
				"x": 377.2437286376953,
				"y": 307.1674346923828,
				"z": -14.215847253799438
			},
			{
				"x": 378.68587493896484,
				"y": 309.9015712738037,
				"z": -13.223772048950195,
				"name": "lips"
			},
			{
				"x": 383.8992691040039,
				"y": 290.29629707336426,
				"z": -9.97326910495758
			},
			{
				"x": 423.3871841430664,
				"y": 271.91688537597656,
				"z": 74.37058925628662,
				"name": "faceOval"
			},
			{
				"x": 377.68043518066406,
				"y": 304.62209701538086,
				"z": -7.603961229324341,
				"name": "lips"
			},
			{
				"x": 379.00428771972656,
				"y": 304.9314594268799,
				"z": -8.57852816581726
			},
			{
				"x": 364.00279998779297,
				"y": 275.2813911437988,
				"z": -19.25792098045349
			},
			{
				"x": 374.68231201171875,
				"y": 273.82555961608887,
				"z": -11.28047227859497
			},
			{
				"x": 365.0354766845703,
				"y": 273.4548568725586,
				"z": -18.791062831878662
			},
			{
				"x": 380.61901092529297,
				"y": 249.8848056793213,
				"z": .15501167625188828
			},
			{
				"x": 391.14158630371094,
				"y": 254.7934627532959,
				"z": 2.0906515419483185
			},
			{
				"x": 378.1761169433594,
				"y": 264.9612236022949,
				"z": -12.605184316635132
			},
			{
				"x": 400.9540557861328,
				"y": 179.99592304229736,
				"z": 27.82477855682373,
				"name": "faceOval"
			},
			{
				"x": 398.0038833618164,
				"y": 188.50656509399414,
				"z": 16.094952821731567
			},
			{
				"x": 394.8717498779297,
				"y": 199.0359592437744,
				"z": 6.226727366447449,
				"name": "leftEyebrow"
			},
			{
				"x": 382.10926055908203,
				"y": 316.83926582336426,
				"z": -8.946179747581482
			},
			{
				"x": 366.51588439941406,
				"y": 200.32583713531494,
				"z": -5.24632453918457,
				"name": "leftEyebrow"
			},
			{
				"x": 367.4893569946289,
				"y": 183.87210845947266,
				"z": 1.9039081037044525
			},
			{
				"x": 368.6243438720703,
				"y": 168.8127565383911,
				"z": 8.736093044281006,
				"name": "faceOval"
			},
			{
				"x": 398.96175384521484,
				"y": 234.9675178527832,
				"z": 13.713973760604858
			},
			{
				"x": 412.9645538330078,
				"y": 242.23042488098145,
				"z": 23.272905349731445
			},
			{
				"x": 372.05257415771484,
				"y": 231.41919136047363,
				"z": 9.226294755935669
			},
			{
				"x": 406.0722351074219,
				"y": 223.58965873718262,
				"z": 18.370890617370605
			},
			{
				"x": 368.27442169189453,
				"y": 240.2039337158203,
				"z": -4.166713654994965
			},
			{
				"x": 372.3575210571289,
				"y": 260.66442489624023,
				"z": -24.976940155029297
			},
			{
				"x": 419.2244338989258,
				"y": 247.9079246520996,
				"z": 30.299127101898193
			},
			{
				"x": 409.43885803222656,
				"y": 246.60913467407227,
				"z": 16.398411989212036
			},
			{
				"x": 401.69139862060547,
				"y": 248.76328468322754,
				"z": 9.395531415939331
			},
			{
				"x": 389.7608184814453,
				"y": 247.56915092468262,
				"z": 5.841569304466248
			},
			{
				"x": 380.5461883544922,
				"y": 244.55984115600586,
				"z": 4.263003468513489
			},
			{
				"x": 373.25817108154297,
				"y": 240.80214500427246,
				"z": 2.5356262922286987
			},
			{
				"x": 358.77086639404297,
				"y": 229.35615062713623,
				"z": -10.387605428695679
			},
			{
				"x": 419.5793914794922,
				"y": 262.8478717803955,
				"z": 26.5175724029541
			},
			{
				"x": 410.8808898925781,
				"y": 222.51372814178467,
				"z": 22.199130058288574
			},
			{
				"x": 358.45714569091797,
				"y": 268.91467094421387,
				"z": -33.17030906677246
			},
			{
				"x": 373.4129333496094,
				"y": 251.6385841369629,
				"z": -5.771540403366089
			},
			{
				"x": 422.5408172607422,
				"y": 239.23919677734375,
				"z": 74.04378890991211,
				"name": "faceOval"
			},
			{
				"x": 367.8171920776367,
				"y": 236.58040523529053,
				"z": 1.820748895406723
			},
			{
				"x": 378.51959228515625,
				"y": 266.2532329559326,
				"z": -5.74819803237915
			},
			{
				"x": 403.3472442626953,
				"y": 229.05112266540527,
				"z": 19.689764976501465
			},
			{
				"x": 372.34840393066406,
				"y": 256.6451168060303,
				"z": -21.872329711914062
			},
			{
				"x": 422.54566192626953,
				"y": 289.1587829589844,
				"z": 68.67491245269775,
				"name": "faceOval"
			},
			{
				"x": 371.9297409057617,
				"y": 228.90116214752197,
				"z": 11.432201862335205,
				"name": "leftEye"
			},
			{
				"x": 366.21360778808594,
				"y": 251.6158962249756,
				"z": -28.19826364517212
			},
			{
				"x": 409.1571807861328,
				"y": 321.3156223297119,
				"z": 20.2266526222229
			},
			{
				"x": 408.52943420410156,
				"y": 331.44238471984863,
				"z": 31.09278917312622,
				"name": "faceOval"
			},
			{
				"x": 424.2788314819336,
				"y": 267.1992301940918,
				"z": 50.467424392700195
			},
			{
				"x": 415.60352325439453,
				"y": 311.6528606414795,
				"z": 30.579242706298828
			},
			{
				"x": 418.12793731689453,
				"y": 221.59927368164062,
				"z": 46.26569747924805
			},
			{
				"x": 385.68286895751953,
				"y": 346.0184955596924,
				"z": -5.70151150226593
			},
			{
				"x": 357.82936096191406,
				"y": 271.3758373260498,
				"z": -24.836881160736084
			},
			{
				"x": 379.588623046875,
				"y": 257.5071716308594,
				"z": -3.755294680595398
			},
			{
				"x": 417.4592590332031,
				"y": 234.71948146820068,
				"z": 34.5475435256958
			},
			{
				"x": 393.4684371948242,
				"y": 231.58967971801758,
				"z": 11.408859491348267,
				"name": "leftEye"
			},
			{
				"x": 387.8864288330078,
				"y": 232.14245796203613,
				"z": 9.51808214187622,
				"name": "leftEye"
			},
			{
				"x": 382.4981689453125,
				"y": 307.5654888153076,
				"z": -7.522260546684265,
				"name": "lips"
			},
			{
				"x": 419.00169372558594,
				"y": 277.8332805633545,
				"z": 26.424202919006348
			},
			{
				"x": 373.62953186035156,
				"y": 357.6375102996826,
				"z": -5.75986921787262,
				"name": "faceOval"
			},
			{
				"x": 392.8708267211914,
				"y": 347.72446632385254,
				"z": 10.154176950454712,
				"name": "faceOval"
			},
			{
				"x": 400.3953552246094,
				"y": 341.0005187988281,
				"z": 19.39797878265381,
				"name": "faceOval"
			},
			{
				"x": 382.25440979003906,
				"y": 231.66935920715332,
				"z": 8.998700976371765,
				"name": "leftEye"
			},
			{
				"x": 377.14550018310547,
				"y": 230.4228687286377,
				"z": 9.804032444953918,
				"name": "leftEye"
			},
			{
				"x": 373.8358688354492,
				"y": 229.64950561523438,
				"z": 11.292144060134888,
				"name": "leftEye"
			},
			{
				"x": 414.5794677734375,
				"y": 221.67891025543213,
				"z": 29.412097930908203
			},
			{
				"x": 377.00672149658203,
				"y": 225.66201210021973,
				"z": 9.360517263412476,
				"name": "leftEye"
			},
			{
				"x": 382.29530334472656,
				"y": 224.8431158065796,
				"z": 8.32175612449646,
				"name": "leftEye"
			},
			{
				"x": 387.5133514404297,
				"y": 224.49507236480713,
				"z": 8.917000889778137,
				"name": "leftEye"
			},
			{
				"x": 393.15906524658203,
				"y": 225.24795055389404,
				"z": 10.737749338150024,
				"name": "leftEye"
			},
			{
				"x": 397.05554962158203,
				"y": 226.55359268188477,
				"z": 13.002015352249146,
				"name": "leftEye"
			},
			{
				"x": 420.5299377441406,
				"y": 221.014666557312,
				"z": 65.40690422058105,
				"name": "faceOval"
			},
			{
				"x": 397.06920623779297,
				"y": 230.6661558151245,
				"z": 13.807345628738403,
				"name": "leftEye"
			},
			{
				"x": 377.94647216796875,
				"y": 285.1647090911865,
				"z": -13.305472135543823
			},
			{
				"x": 372.1118927001953,
				"y": 267.1267318725586,
				"z": -18.83774757385254
			},
			{
				"x": 364.9968719482422,
				"y": 282.24411964416504,
				"z": -19.818150997161865
			},
			{
				"x": 401.973876953125,
				"y": 331.20131492614746,
				"z": 11.566424369812012
			},
			{
				"x": 394.3083190917969,
				"y": 338.86693954467773,
				"z": 3.142542541027069
			},
			{
				"x": 373.9820861816406,
				"y": 351.4504623413086,
				"z": -13.50388765335083
			},
			{
				"x": 414.3888854980469,
				"y": 321.24735832214355,
				"z": 45.51872253417969,
				"name": "faceOval"
			},
			{
				"x": 373.44234466552734,
				"y": 227.33163356781006,
				"z": 10.626870393753052,
				"name": "leftEye"
			},
			{
				"x": 364.0731430053711,
				"y": 240.31539916992188,
				"z": -13.807345628738403
			},
			{
				"x": 384.2658233642578,
				"y": 353.3793067932129,
				"z": .7385850697755814,
				"name": "faceOval"
			},
			{
				"x": 423.20526123046875,
				"y": 283.5176181793213,
				"z": 47.152724266052246
			},
			{
				"x": 369.42798614501953,
				"y": 304.0898895263672,
				"z": -14.647691249847412,
				"name": "lips"
			},
			{
				"x": 370.63812255859375,
				"y": 305.90051651000977,
				"z": -16.211668252944946
			},
			{
				"x": 371.91192626953125,
				"y": 309.0167713165283,
				"z": -17.84567356109619
			},
			{
				"x": 373.0583953857422,
				"y": 313.3545398712158,
				"z": -17.378815412521362,
				"name": "lips"
			},
			{
				"x": 375.39905548095703,
				"y": 321.09289169311523,
				"z": -13.118728399276733
			},
			{
				"x": 379.2567825317383,
				"y": 304.3582534790039,
				"z": -7.924926280975342
			},
			{
				"x": 381.18797302246094,
				"y": 303.7031364440918,
				"z": -7.843226194381714
			},
			{
				"x": 383.0918502807617,
				"y": 302.4884605407715,
				"z": -7.6506465673446655,
				"name": "lips"
			},
			{
				"x": 389.09461975097656,
				"y": 297.1475315093994,
				"z": -5.5497825145721436
			},
			{
				"x": 411.6408920288086,
				"y": 280.24898529052734,
				"z": 12.02161192893982
			},
			{
				"x": 363.3110809326172,
				"y": 234.27620887756348,
				"z": -6.775286793708801
			},
			{
				"x": 366.0474395751953,
				"y": 223.29872131347656,
				"z": 6.827808618545532
			},
			{
				"x": 370.34427642822266,
				"y": 225.1457118988037,
				"z": 9.558931589126587
			},
			{
				"x": 377.5371551513672,
				"y": 303.60079765319824,
				"z": -7.358860373497009,
				"name": "lips"
			},
			{
				"x": 412.9557800292969,
				"y": 299.53579902648926,
				"z": 19.39797878265381
			},
			{
				"x": 360.0810241699219,
				"y": 221.72012329101562,
				"z": -2.153385728597641
			},
			{
				"x": 379.82784271240234,
				"y": 329.47723388671875,
				"z": -10.48097848892212
			},
			{
				"x": 359.08477783203125,
				"y": 235.7911491394043,
				"z": -18.079102039337158
			},
			{
				"x": 369.6688461303711,
				"y": 251.5407943725586,
				"z": -14.962821006774902
			},
			{
				"x": 369.5555114746094,
				"y": 333.5307312011719,
				"z": -15.67478060722351
			},
			{
				"x": 394.0193176269531,
				"y": 315.6973171234131,
				"z": -.9920747578144073
			},
			{
				"x": 383.78997802734375,
				"y": 272.7268695831299,
				"z": -4.689012169837952
			},
			{
				"x": 387.67765045166016,
				"y": 323.6722755432129,
				"z": -5.640236139297485
			},
			{
				"x": 397.8769302368164,
				"y": 272.1331214904785,
				"z": -.9395531564950943
			},
			{
				"x": 389.87476348876953,
				"y": 280.5630111694336,
				"z": -4.29218202829361
			},
			{
				"x": 403.83888244628906,
				"y": 285.1167869567871,
				"z": 3.0229100584983826
			},
			{
				"x": 372.5467300415039,
				"y": 343.1070327758789,
				"z": -16.153310537338257
			},
			{
				"x": 374.1112518310547,
				"y": 256.3721466064453,
				"z": -10.574349164962769
			},
			{
				"x": 399.73785400390625,
				"y": 321.77515983581543,
				"z": 4.849494695663452
			},
			{
				"x": 392.03365325927734,
				"y": 330.56447982788086,
				"z": -1.3407598435878754
			},
			{
				"x": 398.59134674072266,
				"y": 305.93902587890625,
				"z": 1.517290621995926
			},
			{
				"x": 417.95997619628906,
				"y": 290.9716987609863,
				"z": 26.89105987548828
			},
			{
				"x": 406.04541778564453,
				"y": 307.35154151916504,
				"z": 8.666064143180847
			},
			{
				"x": 420.75328826904297,
				"y": 298.40752601623535,
				"z": 41.78385257720947
			},
			{
				"x": 395.4522705078125,
				"y": 291.4153575897217,
				"z": -2.1752697229385376
			},
			{
				"x": 368.6452102661133,
				"y": 245.8882999420166,
				"z": -9.453888535499573
			},
			{
				"x": 370.34900665283203,
				"y": 263.56690406799316,
				"z": -26.75100326538086
			},
			{
				"x": 374.98477935791016,
				"y": 266.6126346588135,
				"z": -19.77146625518799
			},
			{
				"x": 366.99840545654297,
				"y": 258.12140464782715,
				"z": -31.372904777526855
			},
			{
				"x": 371.00616455078125,
				"y": 217.63479709625244,
				"z": 5.60522198677063
			},
			{
				"x": 381.30577087402344,
				"y": 214.14087295532227,
				"z": 4.983716309070587
			},
			{
				"x": 390.1496124267578,
				"y": 213.38221549987793,
				"z": 5.593550801277161
			},
			{
				"x": 397.7696990966797,
				"y": 214.3659782409668,
				"z": 8.57852816581726
			},
			{
				"x": 403.1652069091797,
				"y": 217.65509605407715,
				"z": 13.013685941696167
			},
			{
				"x": 407.3551940917969,
				"y": 230.72525024414062,
				"z": 22.444231510162354
			},
			{
				"x": 424.0876770019531,
				"y": 251.7839241027832,
				"z": 51.16771221160889
			},
			{
				"x": 403.50196838378906,
				"y": 239.88757610321045,
				"z": 15.803166627883911
			},
			{
				"x": 397.31719970703125,
				"y": 241.49806022644043,
				"z": 11.233787536621094
			},
			{
				"x": 388.99425506591797,
				"y": 241.4366912841797,
				"z": 7.948269248008728
			},
			{
				"x": 380.7804489135742,
				"y": 239.78078842163086,
				"z": 6.600214838981628
			},
			{
				"x": 374.01336669921875,
				"y": 237.11946487426758,
				"z": 6.349278092384338
			},
			{
				"x": 369.39125061035156,
				"y": 234.35351371765137,
				"z": 5.987462401390076
			},
			{
				"x": 422.9730987548828,
				"y": 255.76455116271973,
				"z": 76.61150932312012,
				"name": "faceOval"
			},
			{
				"x": 374.73915100097656,
				"y": 269.24214363098145,
				"z": -16.608498096466064
			},
			{
				"x": 364.61681365966797,
				"y": 245.71088790893555,
				"z": -20.02823829650879
			},
			{
				"x": 365.3834533691406,
				"y": 263.34174156188965,
				"z": -32.32996463775635
			},
			{
				"x": 361.58252716064453,
				"y": 267.8273677825928,
				"z": -30.345816612243652
			},
			{
				"x": 365.37208557128906,
				"y": 265.0249671936035,
				"z": -29.178667068481445
			},
			{
				"x": 372.72605895996094,
				"y": 272.05135345458984,
				"z": -14.834434986114502
			},
			{
				"x": 360.48614501953125,
				"y": 268.34827423095703,
				"z": -32.189905643463135
			},
			{
				"x": 359.9516296386719,
				"y": 270.8049201965332,
				"z": -24.650139808654785
			},
			{
				"x": 369.5049285888672,
				"y": 229.01945114135742,
				"z": 10.107489824295044
			},
			{
				"x": 365.5447769165039,
				"y": 230.24096488952637,
				"z": 5.593550801277161
			},
			{
				"x": 363.50669860839844,
				"y": 230.6208372116089,
				"z": .43622106313705444
			},
			{
				"x": 399.3529510498047,
				"y": 227.65677452087402,
				"z": 15.35965085029602,
				"name": "leftEye"
			},
			{
				"x": 402.5693130493164,
				"y": 224.60190296173096,
				"z": 15.931552648544312
			}
		],
		"box": {
			"xMin": 277.8318977355957,
			"yMin": 168.7741756439209,
			"xMax": 424.2788314819336,
			"yMax": 359.8348903656006,
			"width": 146.4469337463379,
			"height": 191.0607147216797
		}
	},
	SAMPLE_FACELANDMARKER_RESULT: {
		"faceLandmarks": [[
			{
				"x": .5760777592658997,
				"y": .8639070391654968,
				"z": -.030997956171631813
			},
			{
				"x": .572094738483429,
				"y": .7886289358139038,
				"z": -.07189624011516571
			},
			{
				"x": .5723551511764526,
				"y": .8075382709503174,
				"z": -.03578168898820877
			},
			{
				"x": .5548420548439026,
				"y": .7188365459442139,
				"z": -.057787876576185226
			},
			{
				"x": .5706077814102173,
				"y": .7674974799156189,
				"z": -.07740399986505508
			},
			{
				"x": .5681378245353699,
				"y": .7387768030166626,
				"z": -.07356284558773041
			},
			{
				"x": .5621535181999207,
				"y": .6681165099143982,
				"z": -.04189874976873398
			},
			{
				"x": .46613582968711853,
				"y": .6679812073707581,
				"z": .011289681307971478
			},
			{
				"x": .5579932928085327,
				"y": .6174106597900391,
				"z": -.03502821549773216
			},
			{
				"x": .5563451647758484,
				"y": .5905600190162659,
				"z": -.03928658738732338
			},
			{
				"x": .5487832427024841,
				"y": .4900572597980499,
				"z": -.029898937791585922
			},
			{
				"x": .5765544176101685,
				"y": .8692144751548767,
				"z": -.02831427752971649
			},
			{
				"x": .5771114230155945,
				"y": .873644232749939,
				"z": -.02345779910683632
			},
			{
				"x": .5771905779838562,
				"y": .877016007900238,
				"z": -.016658689826726913
			},
			{
				"x": .5778058767318726,
				"y": .8770116567611694,
				"z": -.014505492523312569
			},
			{
				"x": .5783766508102417,
				"y": .8835000991821289,
				"z": -.015996402129530907
			},
			{
				"x": .5792440176010132,
				"y": .8913810849189758,
				"z": -.01924579218029976
			},
			{
				"x": .5796768069267273,
				"y": .8996334671974182,
				"z": -.018261712044477463
			},
			{
				"x": .5817288160324097,
				"y": .9255813956260681,
				"z": -.007126849144697189
			},
			{
				"x": .5726592540740967,
				"y": .7992473244667053,
				"z": -.0643521398305893
			},
			{
				"x": .5579419136047363,
				"y": .7996989488601685,
				"z": -.04566684365272522
			},
			{
				"x": .4216199815273285,
				"y": .5958762764930725,
				"z": .06776496022939682
			},
			{
				"x": .5052269697189331,
				"y": .6796539425849915,
				"z": -.0010737782577052712
			},
			{
				"x": .49243026971817017,
				"y": .6838865876197815,
				"z": -.0005227324436418712
			},
			{
				"x": .4796970784664154,
				"y": .6856290102005005,
				"z": .002684245817363262
			},
			{
				"x": .4618356227874756,
				"y": .6764569878578186,
				"z": .013439622707664967
			},
			{
				"x": .5160380601882935,
				"y": .6737282276153564,
				"z": -17607348127057776e-21
			},
			{
				"x": .48070961236953735,
				"y": .6255870461463928,
				"z": -.008339674212038517
			},
			{
				"x": .49719780683517456,
				"y": .6256808042526245,
				"z": -.008027955889701843
			},
			{
				"x": .46674346923828125,
				"y": .6317623853683472,
				"z": -.004460199736058712
			},
			{
				"x": .4582492709159851,
				"y": .641118049621582,
				"z": .0011905613355338573
			},
			{
				"x": .45408669114112854,
				"y": .6911458969116211,
				"z": .020514748990535736
			},
			{
				"x": .535312294960022,
				"y": .9619986414909363,
				"z": .012499462813138962
			},
			{
				"x": .4608460068702698,
				"y": .6628725528717041,
				"z": .01517564244568348
			},
			{
				"x": .4206731915473938,
				"y": .6828458309173584,
				"z": .07848648726940155
			},
			{
				"x": .4390624463558197,
				"y": .6796106696128845,
				"z": .03283142298460007
			},
			{
				"x": .5029968619346619,
				"y": .7701570391654968,
				"z": -.009734481573104858
			},
			{
				"x": .5595027208328247,
				"y": .8607323169708252,
				"z": -.030043255537748337
			},
			{
				"x": .5621269941329956,
				"y": .8738374710083008,
				"z": -.021709579974412918
			},
			{
				"x": .5451499819755554,
				"y": .865527331829071,
				"z": -.022014077752828598
			},
			{
				"x": .5351184010505676,
				"y": .8705098032951355,
				"z": -.011602800339460373
			},
			{
				"x": .5495014190673828,
				"y": .8744956254959106,
				"z": -.016490943729877472
			},
			{
				"x": .5395170450210571,
				"y": .8759440779685974,
				"z": -.007333362940698862
			},
			{
				"x": .5183624029159546,
				"y": .8959754705429077,
				"z": .010520773939788342
			},
			{
				"x": .5604349374771118,
				"y": .7895449995994568,
				"z": -.07082037627696991
			},
			{
				"x": .557381272315979,
				"y": .7687489986419678,
				"z": -.07590588927268982
			},
			{
				"x": .4432901442050934,
				"y": .6308897733688354,
				"z": .0027153254486620426
			},
			{
				"x": .5258325338363647,
				"y": .7151225805282593,
				"z": -.014676518738269806
			},
			{
				"x": .5271827578544617,
				"y": .7833116054534912,
				"z": -.037643320858478546
			},
			{
				"x": .5257382988929749,
				"y": .7717816233634949,
				"z": -.03401920944452286
			},
			{
				"x": .46516409516334534,
				"y": .7705106735229492,
				"z": .0065747760236263275
			},
			{
				"x": .5558893084526062,
				"y": .7420997619628906,
				"z": -.0694495290517807
			},
			{
				"x": .4720408320426941,
				"y": .6066038608551025,
				"z": -.021204356104135513
			},
			{
				"x": .45432573556900024,
				"y": .6158540844917297,
				"z": -.011054684408009052
			},
			{
				"x": .4305151402950287,
				"y": .5608053803443909,
				"z": .0396830290555954
			},
			{
				"x": .5310865640640259,
				"y": .6157484650611877,
				"z": -.03081176057457924
			},
			{
				"x": .5114666223526001,
				"y": .6329749226570129,
				"z": -.00335998204536736
			},
			{
				"x": .506435751914978,
				"y": .8786543607711792,
				"z": .012980876490473747
			},
			{
				"x": .4480472207069397,
				"y": .8640613555908203,
				"z": .12569651007652283
			},
			{
				"x": .5372058153152466,
				"y": .7942581176757812,
				"z": -.03168361634016037
			},
			{
				"x": .5488379597663879,
				"y": .8001630306243896,
				"z": -.03280917927622795
			},
			{
				"x": .5213388204574585,
				"y": .8794381618499756,
				"z": .011892606504261494
			},
			{
				"x": .5242055654525757,
				"y": .8789222240447998,
				"z": .008370225317776203
			},
			{
				"x": .4477175176143646,
				"y": .6039950251579285,
				"z": -.0050799972377717495
			},
			{
				"x": .526964008808136,
				"y": .7916748523712158,
				"z": -.02968614175915718
			},
			{
				"x": .4971255660057068,
				"y": .6050706505775452,
				"z": -.028175678104162216
			},
			{
				"x": .4938119053840637,
				"y": .5882453918457031,
				"z": -.03210941329598427
			},
			{
				"x": .4757143557071686,
				"y": .5094879865646362,
				"z": -.01300730835646391
			},
			{
				"x": .43947282433509827,
				"y": .5816648006439209,
				"z": .01415177434682846
			},
			{
				"x": .485664039850235,
				"y": .5477864146232605,
				"z": -.023685332387685776
			},
			{
				"x": .43635931611061096,
				"y": .6226438283920288,
				"z": .013606148771941662
			},
			{
				"x": .42910251021385193,
				"y": .6102726459503174,
				"z": .03926564007997513
			},
			{
				"x": .5605402588844299,
				"y": .8680099248886108,
				"z": -.027318159118294716
			},
			{
				"x": .5474816560745239,
				"y": .8702861070632935,
				"z": -.019686367362737656
			},
			{
				"x": .5373021364212036,
				"y": .8728838562965393,
				"z": -.010484928265213966
			},
			{
				"x": .540735125541687,
				"y": .7979167103767395,
				"z": -.029073253273963928
			},
			{
				"x": .5228585004806519,
				"y": .87913578748703,
				"z": .009915109723806381
			},
			{
				"x": .530497670173645,
				"y": .8815253973007202,
				"z": .0020524784922599792
			},
			{
				"x": .5259912610054016,
				"y": .8790552616119385,
				"z": .007895970717072487
			},
			{
				"x": .5433906316757202,
				"y": .7882310748100281,
				"z": -.05121905356645584
			},
			{
				"x": .541388213634491,
				"y": .8777219653129578,
				"z": -.00466804439201951
			},
			{
				"x": .5515822172164917,
				"y": .8767023086547852,
				"z": -.010475946590304375
			},
			{
				"x": .5637003779411316,
				"y": .877059817314148,
				"z": -.015273625031113625
			},
			{
				"x": .5640299320220947,
				"y": .9263423085212708,
				"z": -.00658724969252944
			},
			{
				"x": .5642300248146057,
				"y": .8993074893951416,
				"z": -.017653480172157288
			},
			{
				"x": .5637336373329163,
				"y": .8910360932350159,
				"z": -.01852807030081749
			},
			{
				"x": .5637134313583374,
				"y": .8837276697158813,
				"z": -.01482592523097992
			},
			{
				"x": .564205527305603,
				"y": .8768964409828186,
				"z": -.01331155002117157
			},
			{
				"x": .5419867634773254,
				"y": .8778373599052429,
				"z": -.0037720394320786
			},
			{
				"x": .5404468774795532,
				"y": .880696177482605,
				"z": -.005610354244709015
			},
			{
				"x": .5392338633537292,
				"y": .8845721483230591,
				"z": -.007352025713771582
			},
			{
				"x": .538469672203064,
				"y": .8891173601150513,
				"z": -.005154991988092661
			},
			{
				"x": .5189250111579895,
				"y": .8452741503715515,
				"z": -.009755070321261883
			},
			{
				"x": .4258975088596344,
				"y": .7662280797958374,
				"z": .1387351155281067
			},
			{
				"x": .5725725293159485,
				"y": .8041572570800781,
				"z": -.04583907872438431
			},
			{
				"x": .5342061519622803,
				"y": .8785833120346069,
				"z": .002659974154084921
			},
			{
				"x": .5324031114578247,
				"y": .8804071545600891,
				"z": .0017832003068178892
			},
			{
				"x": .5538818836212158,
				"y": .8078407645225525,
				"z": -.03254539892077446
			},
			{
				"x": .5325431823730469,
				"y": .8026832938194275,
				"z": -.019140373915433884
			},
			{
				"x": .5514076948165894,
				"y": .8043903112411499,
				"z": -.03313535451889038
			},
			{
				"x": .5131856203079224,
				"y": .7284771800041199,
				"z": -.009399853646755219
			},
			{
				"x": .49331504106521606,
				"y": .7443980574607849,
				"z": -.005225230939686298
			},
			{
				"x": .5239617824554443,
				"y": .7807451486587524,
				"z": -.025881027802824974
			},
			{
				"x": .4473606050014496,
				"y": .5315827131271362,
				"z": .011164786294102669
			},
			{
				"x": .45718759298324585,
				"y": .5604941248893738,
				"z": -.005943301599472761
			},
			{
				"x": .4670005738735199,
				"y": .5909327268600464,
				"z": -.019681761041283607
			},
			{
				"x": .5311570167541504,
				"y": .9076261520385742,
				"z": .00389476353302598
			},
			{
				"x": .5249923467636108,
				"y": .5893563628196716,
				"z": -.037981919944286346
			},
			{
				"x": .5166932344436646,
				"y": .5429551005363464,
				"z": -.03319704160094261
			},
			{
				"x": .5085030198097229,
				"y": .49676206707954407,
				"z": -.02691275253891945
			},
			{
				"x": .4687720239162445,
				"y": .6834565997123718,
				"z": .008113506250083447
			},
			{
				"x": .4426414966583252,
				"y": .7069531679153442,
				"z": .028577271848917007
			},
			{
				"x": .5230373740196228,
				"y": .6675713658332825,
				"z": .001773772411979735
			},
			{
				"x": .4481240212917328,
				"y": .6527872085571289,
				"z": .012414850294589996
			},
			{
				"x": .5339856743812561,
				"y": .7012367844581604,
				"z": -.020220188423991203
			},
			{
				"x": .5347223281860352,
				"y": .7761190533638,
				"z": -.05141595005989075
			},
			{
				"x": .4315067231655121,
				"y": .7211957573890686,
				"z": .04381405934691429
			},
			{
				"x": .45203351974487305,
				"y": .7206180095672607,
				"z": .017288070172071457
			},
			{
				"x": .46892452239990234,
				"y": .7265436053276062,
				"z": .005602988880127668
			},
			{
				"x": .49314674735069275,
				"y": .7202282547950745,
				"z": -.0006408205372281373
			},
			{
				"x": .5104925632476807,
				"y": .7091827392578125,
				"z": -.00362918758764863
			},
			{
				"x": .5232142210006714,
				"y": .698553740978241,
				"z": -.00787867046892643
			},
			{
				"x": .5497883558273315,
				"y": .6743605136871338,
				"z": -.036349106580019
			},
			{
				"x": .43658503890037537,
				"y": .7627100348472595,
				"z": .042555369436740875
			},
			{
				"x": .4397648870944977,
				"y": .6528646349906921,
				"z": .017956094816327095
			},
			{
				"x": .5653332471847534,
				"y": .7992802858352661,
				"z": -.06365057826042175
			},
			{
				"x": .5285563468933105,
				"y": .736810564994812,
				"z": -.018836988136172295
			},
			{
				"x": .4180678725242615,
				"y": .6792560815811157,
				"z": .12284679710865021
			},
			{
				"x": .5328429937362671,
				"y": .6865872144699097,
				"z": -.010484723374247551
			},
			{
				"x": .5230283141136169,
				"y": .7809416055679321,
				"z": -.011922398582100868
			},
			{
				"x": .4551771283149719,
				"y": .6650775074958801,
				"z": .01774493046104908
			},
			{
				"x": .5337203741073608,
				"y": .7618928551673889,
				"z": -.04697106033563614
			},
			{
				"x": .43463975191116333,
				"y": .8133478164672852,
				"z": .1354849934577942
			},
			{
				"x": .5225707292556763,
				"y": .6605283617973328,
				"z": .004980515688657761
			},
			{
				"x": .5441933870315552,
				"y": .7497199773788452,
				"z": -.06091512367129326
			},
			{
				"x": .4774007797241211,
				"y": .9159183502197266,
				"z": .059622734785079956
			},
			{
				"x": .48068761825561523,
				"y": .9364941716194153,
				"z": .08404944837093353
			},
			{
				"x": .4268292486667633,
				"y": .7657528519630432,
				"z": .09051097184419632
			},
			{
				"x": .46051913499832153,
				"y": .8880485892295837,
				"z": .0738474428653717
			},
			{
				"x": .4243420660495758,
				"y": .6434382200241089,
				"z": .06230505183339119
			},
			{
				"x": .5342157483100891,
				"y": .9835634231567383,
				"z": .021662971004843712
			},
			{
				"x": .5668109655380249,
				"y": .8042187094688416,
				"z": -.044937074184417725
			},
			{
				"x": .5176341533660889,
				"y": .7530587315559387,
				"z": -.012967454269528389
			},
			{
				"x": .430206298828125,
				"y": .6835605502128601,
				"z": .04612284153699875
			},
			{
				"x": .4794231951236725,
				"y": .6732114553451538,
				"z": .003970044665038586
			},
			{
				"x": .49073347449302673,
				"y": .6722435355186462,
				"z": .0008692514384165406
			},
			{
				"x": .5294116139411926,
				"y": .884677529335022,
				"z": .004413890186697245
			},
			{
				"x": .4430122375488281,
				"y": .80235356092453,
				"z": .04987282305955887
			},
			{
				"x": .5603825449943542,
				"y": 1.0092442035675049,
				"z": .026417359709739685
			},
			{
				"x": .5186598300933838,
				"y": .9828659892082214,
				"z": .0513598807156086
			},
			{
				"x": .5010536909103394,
				"y": .9640932679176331,
				"z": .06591596454381943
			},
			{
				"x": .5524769425392151,
				"y": .539441704750061,
				"z": -.035816047340631485
			},
			{
				"x": .5879997611045837,
				"y": 1.0091472864151,
				"z": .02285068854689598
			},
			{
				"x": .5016193985939026,
				"y": .6684437990188599,
				"z": .00028415941051207483
			},
			{
				"x": .511952817440033,
				"y": .6642197370529175,
				"z": .0021144719794392586
			},
			{
				"x": .5194343328475952,
				"y": .6623469591140747,
				"z": .004674181342124939
			},
			{
				"x": .4321230351924896,
				"y": .6496355533599854,
				"z": .03124697133898735
			},
			{
				"x": .508686363697052,
				"y": .6479565501213074,
				"z": -.00044765998609364033
			},
			{
				"x": .4963986277580261,
				"y": .6431032419204712,
				"z": -.0032507688738405704
			},
			{
				"x": .4845542013645172,
				"y": .6430778503417969,
				"z": -.002903624437749386
			},
			{
				"x": .4733612537384033,
				"y": .647506833076477,
				"z": .00023347247042693198
			},
			{
				"x": .4668654501438141,
				"y": .653346598148346,
				"z": .004762572236359119
			},
			{
				"x": .41815051436424255,
				"y": .633708119392395,
				"z": .09809435904026031
			},
			{
				"x": .47159942984580994,
				"y": .6711485385894775,
				"z": .007849935442209244
			},
			{
				"x": .5734396576881409,
				"y": .8256140351295471,
				"z": -.03155219927430153
			},
			{
				"x": .5306524038314819,
				"y": .8337990641593933,
				"z": -.018351426348090172
			},
			{
				"x": .5371729135513306,
				"y": .7910830974578857,
				"z": -.037286680191755295
			},
			{
				"x": .5549534559249878,
				"y": .8275275826454163,
				"z": -.030664825811982155
			},
			{
				"x": .5597432255744934,
				"y": .6418541669845581,
				"z": -.03318847343325615
			},
			{
				"x": .4958484172821045,
				"y": .9429569244384766,
				"z": .048340678215026855
			},
			{
				"x": .5140507817268372,
				"y": .9634028077125549,
				"z": .03589847311377525
			},
			{
				"x": .5587693452835083,
				"y": .9951097369194031,
				"z": .00908728688955307
			},
			{
				"x": .46411189436912537,
				"y": .9051855206489563,
				"z": .10601935535669327
			},
			{
				"x": .5181609392166138,
				"y": .6554316878318787,
				"z": .002546071307733655
			},
			{
				"x": .5436590909957886,
				"y": .7085841298103333,
				"z": -.03844436630606651
			},
			{
				"x": .5872187614440918,
				"y": .9960382580757141,
				"z": .0063423276878893375
			},
			{
				"x": .5379653573036194,
				"y": .9989125728607178,
				"z": .03636329993605614
			},
			{
				"x": .4350326955318451,
				"y": .8088565468788147,
				"z": .09147704392671585
			},
			{
				"x": .5523084998130798,
				"y": .8773422837257385,
				"z": -.009068487212061882
			},
			{
				"x": .5510149598121643,
				"y": .8816931843757629,
				"z": -.011043853126466274
			},
			{
				"x": .5503793954849243,
				"y": .88776695728302,
				"z": -.01348799467086792
			},
			{
				"x": .5501549243927002,
				"y": .8954370617866516,
				"z": -.012142189778387547
			},
			{
				"x": .546072781085968,
				"y": .9192524552345276,
				"z": -.003157563041895628
			},
			{
				"x": .5314661860466003,
				"y": .8771666884422302,
				"z": .0005075141089037061
			},
			{
				"x": .5293324589729309,
				"y": .8762547969818115,
				"z": .00039177737198770046
			},
			{
				"x": .5275698900222778,
				"y": .8750609755516052,
				"z": 47732755774632096e-21
			},
			{
				"x": .5104271173477173,
				"y": .8607332110404968,
				"z": .0012934643309563398
			},
			{
				"x": .45938700437545776,
				"y": .8134918212890625,
				"z": .023569690063595772
			},
			{
				"x": .5418947339057922,
				"y": .6864100694656372,
				"z": -.027333909645676613
			},
			{
				"x": .531914234161377,
				"y": .6456130743026733,
				"z": -.005434140563011169
			},
			{
				"x": .523697018623352,
				"y": .647885262966156,
				"z": -.0002466466394253075
			},
			{
				"x": .5338191390037537,
				"y": .8783687353134155,
				"z": .002268768846988678
			},
			{
				"x": .46226605772972107,
				"y": .8610277771949768,
				"z": .04718952998518944
			},
			{
				"x": .5434442758560181,
				"y": .6456181406974792,
				"z": -.02327350154519081
			},
			{
				"x": .5399754643440247,
				"y": .940219521522522,
				"z": .005075343884527683
			},
			{
				"x": .5661457777023315,
				"y": .71457839012146,
				"z": -.06242101639509201
			},
			{
				"x": .5523148775100708,
				"y": .6974870562553406,
				"z": -.04863070324063301
			},
			{
				"x": .5639959573745728,
				"y": .6923378109931946,
				"z": -.05180761218070984
			},
			{
				"x": .5367592573165894,
				"y": .7423217296600342,
				"z": -.03623027727007866
			},
			{
				"x": .5853689908981323,
				"y": .9752064943313599,
				"z": -.002361974213272333
			},
			{
				"x": .5835235118865967,
				"y": .9493685960769653,
				"z": -.003941743168979883
			},
			{
				"x": .5615018606185913,
				"y": .949194610118866,
				"z": -.0015953965485095978
			},
			{
				"x": .5068561434745789,
				"y": .9048219323158264,
				"z": .01862684078514576
			},
			{
				"x": .5134067535400391,
				"y": .7971825003623962,
				"z": -.008485661819577217
			},
			{
				"x": .5223897099494934,
				"y": .925589919090271,
				"z": .01249657291918993
			},
			{
				"x": .48500555753707886,
				"y": .7959478497505188,
				"z": -.0032065745908766985
			},
			{
				"x": .5037734508514404,
				"y": .8184596300125122,
				"z": -.004932103678584099
			},
			{
				"x": .4766361117362976,
				"y": .828806459903717,
				"z": .01027688942849636
			},
			{
				"x": .5589827299118042,
				"y": .974656343460083,
				"z": .0009666886180639267
			},
			{
				"x": .5294582843780518,
				"y": .7541216611862183,
				"z": -.025603046640753746
			},
			{
				"x": .4973002076148987,
				"y": .9208990931510925,
				"z": .031931452453136444
			},
			{
				"x": .5163551568984985,
				"y": .9432790875434875,
				"z": .024321340024471283
			},
			{
				"x": .49399662017822266,
				"y": .8814862370491028,
				"z": .018687399104237556
			},
			{
				"x": .44948166608810425,
				"y": .836137592792511,
				"z": .05702034756541252
			},
			{
				"x": .47898444533348083,
				"y": .8836610913276672,
				"z": .03150695189833641
			},
			{
				"x": .4454479217529297,
				"y": .8499438166618347,
				"z": .08868525922298431
			},
			{
				"x": .49572959542274475,
				"y": .8452823758125305,
				"z": .0036111653316766024
			},
			{
				"x": .5362502336502075,
				"y": .7222585678100586,
				"z": -.027912352234125137
			},
			{
				"x": .5393770337104797,
				"y": .7850722074508667,
				"z": -.05415399745106697
			},
			{
				"x": .531399667263031,
				"y": .7898418307304382,
				"z": -.03883346915245056
			},
			{
				"x": .5451627373695374,
				"y": .7717036604881287,
				"z": -.06480253487825394
			},
			{
				"x": .5206395983695984,
				"y": .6287745833396912,
				"z": -.010521138086915016
			},
			{
				"x": .4974782466888428,
				"y": .6191938519477844,
				"z": -.014098240062594414
			},
			{
				"x": .4774145185947418,
				"y": .6193130612373352,
				"z": -.013643337413668633
			},
			{
				"x": .4616098403930664,
				"y": .6259890198707581,
				"z": -.008448202162981033
			},
			{
				"x": .4516478478908539,
				"y": .6368461847305298,
				"z": 9050309745362028e-20
			},
			{
				"x": .4485096037387848,
				"y": .6719120740890503,
				"z": .022984720766544342
			},
			{
				"x": .42177659273147583,
				"y": .7240667343139648,
				"z": .08511673659086227
			},
			{
				"x": .4616215229034424,
				"y": .6988231539726257,
				"z": .014238474890589714
			},
			{
				"x": .4755798876285553,
				"y": .7034608721733093,
				"z": .00625590980052948
			},
			{
				"x": .4924992024898529,
				"y": .7005885243415833,
				"z": .0009391739731654525
			},
			{
				"x": .5082254409790039,
				"y": .693384051322937,
				"z": -.0009464038303121924
			},
			{
				"x": .5203112959861755,
				"y": .6849707961082458,
				"z": -.0022114769089967012
			},
			{
				"x": .52867591381073,
				"y": .6779075860977173,
				"z": -.002962538506835699
			},
			{
				"x": .4213953912258148,
				"y": .7219811677932739,
				"z": .1350894570350647
			},
			{
				"x": .5320829749107361,
				"y": .794858992099762,
				"z": -.03181503340601921
			},
			{
				"x": .5452795028686523,
				"y": .7286570072174072,
				"z": -.04771539941430092
			},
			{
				"x": .5496407747268677,
				"y": .7866933345794678,
				"z": -.06452003121376038
			},
			{
				"x": .557040274143219,
				"y": .7962084412574768,
				"z": -.05837344378232956
			},
			{
				"x": .549176812171936,
				"y": .7895247936248779,
				"z": -.057761140167713165
			},
			{
				"x": .5362890362739563,
				"y": .8005836606025696,
				"z": -.026903774589300156
			},
			{
				"x": .560200035572052,
				"y": .7983731031417847,
				"z": -.06172555685043335
			},
			{
				"x": .5616944432258606,
				"y": .8022753596305847,
				"z": -.045200999826192856
			},
			{
				"x": .5273328423500061,
				"y": .6611284017562866,
				"z": .0029021520167589188
			},
			{
				"x": .534850537776947,
				"y": .6660012006759644,
				"z": -.005215510260313749
			},
			{
				"x": .5394860506057739,
				"y": .6701375246047974,
				"z": -.014931917190551758
			},
			{
				"x": .4634307324886322,
				"y": .658291757106781,
				"z": .009295716881752014
			},
			{
				"x": .4538393020629883,
				"y": .6519932150840759,
				"z": .00930330716073513
			},
			{
				"x": .5776031613349915,
				"y": .7159298658370972,
				"z": -.057365912944078445
			},
			{
				"x": .6504855155944824,
				"y": .6461779475212097,
				"z": .014184834435582161
			},
			{
				"x": .5860154032707214,
				"y": .7962266206741333,
				"z": -.04522843658924103
			},
			{
				"x": .6842049360275269,
				"y": .5631637573242188,
				"z": .07207967340946198
			},
			{
				"x": .6152560710906982,
				"y": .6674962639808655,
				"z": .0007529259892180562
			},
			{
				"x": .6280948519706726,
				"y": .6684326529502869,
				"z": .0016892586136236787
			},
			{
				"x": .6408625245094299,
				"y": .6663892269134521,
				"z": .005331226624548435
			},
			{
				"x": .6557814478874207,
				"y": .6534678936004639,
				"z": .01646413467824459
			},
			{
				"x": .6035663485527039,
				"y": .6639701724052429,
				"z": .0013799630105495453
			},
			{
				"x": .6329053044319153,
				"y": .608010470867157,
				"z": -.006195899099111557
			},
			{
				"x": .6167260408401489,
				"y": .6117533445358276,
				"z": -.006319951266050339
			},
			{
				"x": .6471013426780701,
				"y": .6112449765205383,
				"z": -.0017843559617176652
			},
			{
				"x": .6560901999473572,
				"y": .6185776591300964,
				"z": .004047257360070944
			},
			{
				"x": .6666946411132812,
				"y": .6651176810264587,
				"z": .023647578433156013
			},
			{
				"x": .6311345100402832,
				"y": .9495396018028259,
				"z": .014004078693687916
			},
			{
				"x": .6544655561447144,
				"y": .6397901773452759,
				"z": .01809609681367874
			},
			{
				"x": .6965808868408203,
				"y": .6482675075531006,
				"z": .08304904401302338
			},
			{
				"x": .679817259311676,
				"y": .650188148021698,
				"z": .03632688894867897
			},
			{
				"x": .6336516737937927,
				"y": .7541458010673523,
				"z": -.007742783520370722
			},
			{
				"x": .5921701192855835,
				"y": .8567668199539185,
				"z": -.029399123042821884
			},
			{
				"x": .591663658618927,
				"y": .870215654373169,
				"z": -.02103729173541069
			},
			{
				"x": .6068367958068848,
				"y": .8584195375442505,
				"z": -.020668085664510727
			},
			{
				"x": .6176617741584778,
				"y": .860965371131897,
				"z": -.009790095500648022
			},
			{
				"x": .6040634512901306,
				"y": .8686612844467163,
				"z": -.015289564616978168
			},
			{
				"x": .6143736839294434,
				"y": .8671170473098755,
				"z": -.005712216719985008
			},
			{
				"x": .6373105049133301,
				"y": .8815656900405884,
				"z": .012672550976276398
			},
			{
				"x": .5832505822181702,
				"y": .7866312861442566,
				"z": -.07051534950733185
			},
			{
				"x": .5836675763130188,
				"y": .7658692598342896,
				"z": -.07566110789775848
			},
			{
				"x": .6709531545639038,
				"y": .604898989200592,
				"z": .005951565690338612
			},
			{
				"x": .6029891967773438,
				"y": .705652117729187,
				"z": -.013388276100158691
			},
			{
				"x": .6131622195243835,
				"y": .7728396058082581,
				"z": -.036248479038476944
			},
			{
				"x": .6123163104057312,
				"y": .7612020373344421,
				"z": -.03264721855521202
			},
			{
				"x": .6696187853813171,
				"y": .744706928730011,
				"z": .009673702530562878
			},
			{
				"x": .5803102254867554,
				"y": .7385968565940857,
				"z": -.0689152330160141
			},
			{
				"x": .6404349207878113,
				"y": .5877999663352966,
				"z": -.01929756999015808
			},
			{
				"x": .6588467955589294,
				"y": .5929454565048218,
				"z": -.008487257175147533
			},
			{
				"x": .6720337867736816,
				"y": .530631422996521,
				"z": .043437421321868896
			},
			{
				"x": .584305465221405,
				"y": .6099005341529846,
				"z": -.030301367864012718
			},
			{
				"x": .6034283638000488,
				"y": .6217452883720398,
				"z": -.001970183802768588
			},
			{
				"x": .6460927724838257,
				"y": .8608663082122803,
				"z": .015541625209152699
			},
			{
				"x": .6957815289497375,
				"y": .8326103091239929,
				"z": .13015234470367432
			},
			{
				"x": .6043362617492676,
				"y": .7861682772636414,
				"z": -.030476901680231094
			},
			{
				"x": .594293475151062,
				"y": .7942103147506714,
				"z": -.032218821346759796
			},
			{
				"x": .6324057579040527,
				"y": .8665139675140381,
				"z": .014255806803703308
			},
			{
				"x": .6296147704124451,
				"y": .8667733669281006,
				"z": .010388285852968693
			},
			{
				"x": .663644552230835,
				"y": .5798642635345459,
				"z": -.0022301070857793093
			},
			{
				"x": .6140630841255188,
				"y": .7809288501739502,
				"z": -.02835679054260254
			},
			{
				"x": .615908145904541,
				"y": .5921698212623596,
				"z": -.026804860681295395
			},
			{
				"x": .617181122303009,
				"y": .5748661756515503,
				"z": -.03060605563223362
			},
			{
				"x": .6222207546234131,
				"y": .49137672781944275,
				"z": -.011151673272252083
			},
			{
				"x": .6669357419013977,
				"y": .5541607141494751,
				"z": .017466170713305473
			},
			{
				"x": .6182981729507446,
				"y": .5320425629615784,
				"z": -.021793590858578682
			},
			{
				"x": .6760554313659668,
				"y": .595052182674408,
				"z": .017115700989961624
			},
			{
				"x": .6801463961601257,
				"y": .5800720453262329,
				"z": .043127160519361496
			},
			{
				"x": .5922210812568665,
				"y": .8644017577171326,
				"z": -.02662893570959568
			},
			{
				"x": .6054555177688599,
				"y": .8637874722480774,
				"z": -.018363753333687782
			},
			{
				"x": .6161889433860779,
				"y": .8641164898872375,
				"z": -.008808949030935764
			},
			{
				"x": .6017249822616577,
				"y": .7901403307914734,
				"z": -.028126630932092667
			},
			{
				"x": .631446123123169,
				"y": .8664817810058594,
				"z": .012112865224480629
			},
			{
				"x": .6249198913574219,
				"y": .8716511130332947,
				"z": .003882825840264559
			},
			{
				"x": .6281915903091431,
				"y": .867301881313324,
				"z": .009891441091895103
			},
			{
				"x": .5986843109130859,
				"y": .7813931703567505,
				"z": -.050227612257003784
			},
			{
				"x": .6126407384872437,
				"y": .869275689125061,
				"z": -.0031255714129656553
			},
			{
				"x": .6027271151542664,
				"y": .8711842894554138,
				"z": -.009324162267148495
			},
			{
				"x": .59088134765625,
				"y": .8742044568061829,
				"z": -.014608660712838173
			},
			{
				"x": .5984604358673096,
				"y": .9216185212135315,
				"z": -.005981989670544863
			},
			{
				"x": .5950398445129395,
				"y": .8964707255363464,
				"z": -.01703473925590515
			},
			{
				"x": .5941568613052368,
				"y": .8882410526275635,
				"z": -.017784785479307175
			},
			{
				"x": .5928806662559509,
				"y": .8803883194923401,
				"z": -.014153128489851952
			},
			{
				"x": .5909661054611206,
				"y": .8748103976249695,
				"z": -.012609979137778282
			},
			{
				"x": .6128016710281372,
				"y": .8702545762062073,
				"z": -.0022550546564161777
			},
			{
				"x": .6150846481323242,
				"y": .8726804256439209,
				"z": -.00414019962772727
			},
			{
				"x": .6173093914985657,
				"y": .8770190477371216,
				"z": -.005970994010567665
			},
			{
				"x": .619335412979126,
				"y": .8814800977706909,
				"z": -.0036864024586975574
			},
			{
				"x": .6292637586593628,
				"y": .8314558267593384,
				"z": -.007714875973761082
			},
			{
				"x": .702275276184082,
				"y": .7320667505264282,
				"z": .1433621346950531
			},
			{
				"x": .6204835176467896,
				"y": .8689177632331848,
				"z": .0044869170524179935
			},
			{
				"x": .6223508715629578,
				"y": .8704851269721985,
				"z": .00352082890458405
			},
			{
				"x": .590448260307312,
				"y": .8029727935791016,
				"z": -.03200828656554222
			},
			{
				"x": .6097423434257507,
				"y": .7933741211891174,
				"z": -.018042555078864098
			},
			{
				"x": .59229576587677,
				"y": .7993767261505127,
				"z": -.032564569264650345
			},
			{
				"x": .6171364188194275,
				"y": .7153720259666443,
				"z": -.007672437466681004
			},
			{
				"x": .6389747858047485,
				"y": .726390540599823,
				"z": -.002999067772179842
			},
			{
				"x": .6151940226554871,
				"y": .769412100315094,
				"z": -.024427521973848343
			},
			{
				"x": .6526776552200317,
				"y": .505868136882782,
				"z": .01412637997418642
			},
			{
				"x": .6475822329521179,
				"y": .5375454425811768,
				"z": -.0033899128902703524
			},
			{
				"x": .6433356404304504,
				"y": .5714520215988159,
				"z": -.017428796738386154
			},
			{
				"x": .626949667930603,
				"y": .8962116837501526,
				"z": .005602736957371235
			},
			{
				"x": .5868416428565979,
				"y": .5829002261161804,
				"z": -.03727729618549347
			},
			{
				"x": .5877229571342468,
				"y": .5345035791397095,
				"z": -.032396964728832245
			},
			{
				"x": .5887066125869751,
				"y": .48655083775520325,
				"z": -.025856535881757736
			},
			{
				"x": .6507197618484497,
				"y": .6612282991409302,
				"z": .011114613153040409
			},
			{
				"x": .6803066730499268,
				"y": .677992045879364,
				"z": .032125361263751984
			},
			{
				"x": .5963194370269775,
				"y": .6598632335662842,
				"z": .002976928371936083
			},
			{
				"x": .667536199092865,
				"y": .6274255514144897,
				"z": .015618261881172657
			},
			{
				"x": .5930740833282471,
				"y": .6940041780471802,
				"z": -.019217798486351967
			},
			{
				"x": .6053346395492554,
				"y": .7676517963409424,
				"z": -.050308309495449066
			},
			{
				"x": .6934473514556885,
				"y": .6884298920631409,
				"z": .04794462397694588
			},
			{
				"x": .6738007664680481,
				"y": .6934011578559875,
				"z": .020697161555290222
			},
			{
				"x": .6588084697723389,
				"y": .7033141851425171,
				"z": .008462334051728249
			},
			{
				"x": .6346072554588318,
				"y": .7029502391815186,
				"z": .001542167621664703
			},
			{
				"x": .6157816648483276,
				"y": .6966525912284851,
				"z": -.002009218093007803
			},
			{
				"x": .6015574336051941,
				"y": .688928484916687,
				"z": -.006588225718587637
			},
			{
				"x": .5746836066246033,
				"y": .6711069345474243,
				"z": -.03597589209675789
			},
			{
				"x": .6947521567344666,
				"y": .7309479117393494,
				"z": .046707939356565475
			},
			{
				"x": .6759101152420044,
				"y": .6249120831489563,
				"z": .021654341369867325
			},
			{
				"x": .5794773101806641,
				"y": .7971615195274353,
				"z": -.06339326500892639
			},
			{
				"x": .6041849851608276,
				"y": .727514922618866,
				"z": -.017512541264295578
			},
			{
				"x": .6968844532966614,
				"y": .6440950036048889,
				"z": .12727996706962585
			},
			{
				"x": .5910853147506714,
				"y": .679325520992279,
				"z": -.009497715160250664
			},
			{
				"x": .6157375574111938,
				"y": .7695677280426025,
				"z": -.010624290443956852
			},
			{
				"x": .6606494784355164,
				"y": .6410489678382874,
				"z": .0208158977329731
			},
			{
				"x": .6040687561035156,
				"y": .7531470656394958,
				"z": -.045887019485235214
			},
			{
				"x": .7012156248092651,
				"y": .780247151851654,
				"z": .14028730988502502
			},
			{
				"x": .595149576663971,
				"y": .6527782678604126,
				"z": .006308757700026035
			},
			{
				"x": .5925500392913818,
				"y": .7436665892601013,
				"z": -.060151755809783936
			},
			{
				"x": .6780198812484741,
				"y": .8905693888664246,
				"z": .0626060739159584
			},
			{
				"x": .676746666431427,
				"y": .9113880395889282,
				"z": .08726003766059875
			},
			{
				"x": .7030686140060425,
				"y": .7312687635421753,
				"z": .09529774636030197
			},
			{
				"x": .688987135887146,
				"y": .8588417172431946,
				"z": .07752864807844162
			},
			{
				"x": .6883691549301147,
				"y": .6109960675239563,
				"z": .06669612973928452
			},
			{
				"x": .6358906030654907,
				"y": .9702065587043762,
				"z": .023120900616049767
			},
			{
				"x": .5781539678573608,
				"y": .8023634552955627,
				"z": -.044763918966054916
			},
			{
				"x": .6170316934585571,
				"y": .7408350706100464,
				"z": -.011375460773706436
			},
			{
				"x": .688542366027832,
				"y": .6516284346580505,
				"z": .050206027925014496
			},
			{
				"x": .6385149359703064,
				"y": .6540714502334595,
				"z": .006462941411882639
			},
			{
				"x": .6279382109642029,
				"y": .6563615798950195,
				"z": .003062846139073372
			},
			{
				"x": .6268895268440247,
				"y": .8736732006072998,
				"z": .00627936702221632
			},
			{
				"x": .6944946050643921,
				"y": .7709181308746338,
				"z": .053824134171009064
			},
			{
				"x": .614617109298706,
				"y": 1.0022112131118774,
				"z": .02719894051551819
			},
			{
				"x": .6493719220161438,
				"y": .9665167927742004,
				"z": .053563784807920456
			},
			{
				"x": .6624587178230286,
				"y": .943530797958374,
				"z": .068605437874794
			},
			{
				"x": .6162528991699219,
				"y": .6558693051338196,
				"z": .002187855076044798
			},
			{
				"x": .6058168411254883,
				"y": .654328465461731,
				"z": .0036193584091961384
			},
			{
				"x": .5987918972969055,
				"y": .6536934971809387,
				"z": .006134530063718557
			},
			{
				"x": .6831037402153015,
				"y": .6195642948150635,
				"z": .03511790186166763
			},
			{
				"x": .6062582731246948,
				"y": .6356398463249207,
				"z": .001280312892049551
			},
			{
				"x": .6174948811531067,
				"y": .62776118516922,
				"z": -.0013642468256875873
			},
			{
				"x": .6297246217727661,
				"y": .6253792643547058,
				"z": -.0007034156005829573
			},
			{
				"x": .6407091617584229,
				"y": .627578616142273,
				"z": .0028144705574959517
			},
			{
				"x": .6479622721672058,
				"y": .6322650909423828,
				"z": .00750273372977972
			},
			{
				"x": .6915091276168823,
				"y": .5990704298019409,
				"z": .10270945727825165
			},
			{
				"x": .6457163095474243,
				"y": .6504453420639038,
				"z": .010696077719330788
			},
			{
				"x": .6164222955703735,
				"y": .8231936097145081,
				"z": -.016772059723734856
			},
			{
				"x": .6042401194572449,
				"y": .7830976843833923,
				"z": -.03630910441279411
			},
			{
				"x": .5922216773033142,
				"y": .8228387236595154,
				"z": -.029992375522851944
			},
			{
				"x": .6646111011505127,
				"y": .92097008228302,
				"z": .050967294722795486
			},
			{
				"x": .651232898235321,
				"y": .9460107088088989,
				"z": .038000158965587616
			},
			{
				"x": .6140977144241333,
				"y": .9882472157478333,
				"z": .009882091544568539
			},
			{
				"x": .6870781183242798,
				"y": .8768675327301025,
				"z": .10980932414531708
			},
			{
				"x": .5986856818199158,
				"y": .6456438899040222,
				"z": .003999010659754276
			},
			{
				"x": .585981547832489,
				"y": .7034481763839722,
				"z": -.0377722829580307
			},
			{
				"x": .6342031359672546,
				"y": .9867448806762695,
				"z": .03786521404981613
			},
			{
				"x": .7013950943946838,
				"y": .776049017906189,
				"z": .09598205983638763
			},
			{
				"x": .6030206680297852,
				"y": .8719133138656616,
				"z": -.007931148633360863
			},
			{
				"x": .6050592064857483,
				"y": .8767156004905701,
				"z": -.009791925549507141
			},
			{
				"x": .6073468923568726,
				"y": .8831382393836975,
				"z": -.012361008673906326
			},
			{
				"x": .6087977290153503,
				"y": .890143632888794,
				"z": -.01098148338496685
			},
			{
				"x": .6147705316543579,
				"y": .9110084772109985,
				"z": -.0018823575228452682
			},
			{
				"x": .622577965259552,
				"y": .8670604825019836,
				"z": .002609190298244357
			},
			{
				"x": .6241236329078674,
				"y": .8651344180107117,
				"z": .0025534380692988634
			},
			{
				"x": .6257084608078003,
				"y": .8638408184051514,
				"z": .0023300074972212315
			},
			{
				"x": .639931321144104,
				"y": .8449671268463135,
				"z": .0038123116828501225
			},
			{
				"x": .6810906529426575,
				"y": .7856625318527222,
				"z": .02717764675617218
			},
			{
				"x": .583532452583313,
				"y": .6811994910240173,
				"z": -.026588857173919678
			},
			{
				"x": .5855660438537598,
				"y": .6393819451332092,
				"z": -.004512844607234001
			},
			{
				"x": .5932201743125916,
				"y": .6398029327392578,
				"z": .0008020466193556786
			},
			{
				"x": .6200879812240601,
				"y": .8683351874351501,
				"z": .00417016725987196
			},
			{
				"x": .6842559576034546,
				"y": .8330534100532532,
				"z": .050836317241191864
			},
			{
				"x": .5754412412643433,
				"y": .6418221592903137,
				"z": -.022838059812784195
			},
			{
				"x": .6232790350914001,
				"y": .9295297265052795,
				"z": .006339520215988159
			},
			{
				"x": .5764067769050598,
				"y": .694546639919281,
				"z": -.04825803264975548
			},
			{
				"x": .59778892993927,
				"y": .7343927621841431,
				"z": -.035004377365112305
			},
			{
				"x": .6042810678482056,
				"y": .9441440105438232,
				"z": -.0010970570147037506
			},
			{
				"x": .6496372222900391,
				"y": .8869078159332275,
				"z": .021036235615611076
			},
			{
				"x": .6274012327194214,
				"y": .7830310463905334,
				"z": -.006658440921455622
			},
			{
				"x": .637792706489563,
				"y": .9104999899864197,
				"z": .014290250837802887
			},
			{
				"x": .6549934148788452,
				"y": .7748609185218811,
				"z": -.0006672973395325243
			},
			{
				"x": .6404005289077759,
				"y": .801220715045929,
				"z": -.0026642554439604282
			},
			{
				"x": .6671456694602966,
				"y": .8045546412467957,
				"z": .013180811889469624
			},
			{
				"x": .6107483506202698,
				"y": .9680658578872681,
				"z": .001778992242179811
			},
			{
				"x": .6060343980789185,
				"y": .744587242603302,
				"z": -.024382334202528
			},
			{
				"x": .6602751612663269,
				"y": .8998945355415344,
				"z": .0344940721988678
			},
			{
				"x": .6463775038719177,
				"y": .9262562394142151,
				"z": .02617623284459114
			},
			{
				"x": .6579852104187012,
				"y": .8602304458618164,
				"z": .021586716175079346
			},
			{
				"x": .6926165223121643,
				"y": .8053340315818787,
				"z": .061075080186128616
			},
			{
				"x": .6724731922149658,
				"y": .8594399690628052,
				"z": .03457934781908989
			},
			{
				"x": .6975721716880798,
				"y": .8183245062828064,
				"z": .09300774335861206
			},
			{
				"x": .6512877941131592,
				"y": .8258221745491028,
				"z": .006324059329926968
			},
			{
				"x": .594887375831604,
				"y": .7148372530937195,
				"z": -.026898479089140892
			},
			{
				"x": .6017440557479858,
				"y": .7773507833480835,
				"z": -.05312420800328255
			},
			{
				"x": .6096571683883667,
				"y": .7806998491287231,
				"z": -.037646256387233734
			},
			{
				"x": .5952993035316467,
				"y": .7654367685317993,
				"z": -.06398405134677887
			},
			{
				"x": .5950021147727966,
				"y": .6201304793357849,
				"z": -.009297547861933708
			},
			{
				"x": .6165438890457153,
				"y": .6052900552749634,
				"z": -.012455573305487633
			},
			{
				"x": .6362661719322205,
				"y": .6015968918800354,
				"z": -.011649220250546932
			},
			{
				"x": .6522727608680725,
				"y": .6046400666236877,
				"z": -.005903332494199276
			},
			{
				"x": .6625409722328186,
				"y": .6128141283988953,
				"z": .0030042496509850025
			},
			{
				"x": .6688099503517151,
				"y": .6457712054252625,
				"z": .026322703808546066
			},
			{
				"x": .7013440728187561,
				"y": .6893666386604309,
				"z": .08984331786632538
			},
			{
				"x": .6608623266220093,
				"y": .6749406456947327,
				"z": .0172116681933403
			},
			{
				"x": .6482325196266174,
				"y": .6823726296424866,
				"z": .008881398476660252
			},
			{
				"x": .6313265562057495,
				"y": .6842025518417358,
				"z": .0031308617908507586
			},
			{
				"x": .6147016286849976,
				"y": .6809731721878052,
				"z": .0007630771724507213
			},
			{
				"x": .6018834114074707,
				"y": .6755372285842896,
				"z": -.0008834321051836014
			},
			{
				"x": .5925027132034302,
				"y": .670681357383728,
				"z": -.001968748401850462
			},
			{
				"x": .700127363204956,
				"y": .6871103644371033,
				"z": .13980500400066376
			},
			{
				"x": .6095665693283081,
				"y": .7853189706802368,
				"z": -.03074747882783413
			},
			{
				"x": .5880423784255981,
				"y": .7229287028312683,
				"z": -.04691500961780548
			},
			{
				"x": .5930182337760925,
				"y": .7811514139175415,
				"z": -.06398335844278336
			},
			{
				"x": .5867722034454346,
				"y": .7922660112380981,
				"z": -.05794971063733101
			},
			{
				"x": .5933279991149902,
				"y": .7842848896980286,
				"z": -.05714067071676254
			},
			{
				"x": .6063535809516907,
				"y": .7920218706130981,
				"z": -.02590685710310936
			},
			{
				"x": .5839452743530273,
				"y": .794978141784668,
				"z": -.0615212507545948
			},
			{
				"x": .5828126072883606,
				"y": .8000800013542175,
				"z": -.0449722595512867
			},
			{
				"x": .5909603834152222,
				"y": .6541213393211365,
				"z": .003991890233010054
			},
			{
				"x": .5852181911468506,
				"y": .6602938771247864,
				"z": -.004428438376635313
			},
			{
				"x": .5825737714767456,
				"y": .6651063561439514,
				"z": -.014345290139317513
			},
			{
				"x": .6517343521118164,
				"y": .6362385153770447,
				"z": .012151890434324741
			},
			{
				"x": .6615052819252014,
				"y": .6281577944755554,
				"z": .0123682152479887
			},
			{
				"x": .4856873154640198,
				"y": .6568945646286011,
				"z": .000720038078725338
			},
			{
				"x": .49988406896591187,
				"y": .6547410488128662,
				"z": .0006949726957827806
			},
			{
				"x": .48438939452171326,
				"y": .6392973065376282,
				"z": .000705525919329375
			},
			{
				"x": .47143134474754333,
				"y": .6589511632919312,
				"z": .0006980331381782889
			},
			{
				"x": .48704618215560913,
				"y": .6752797961235046,
				"z": .0006921177846379578
			},
			{
				"x": .6243702173233032,
				"y": .640461802482605,
				"z": -6592126737814397e-20
			},
			{
				"x": .6390967965126038,
				"y": .6385173797607422,
				"z": -.00016105435497593135
			},
			{
				"x": .6230536699295044,
				"y": .6224825382232666,
				"z": -.00016136496560648084
			},
			{
				"x": .6095397472381592,
				"y": .641917884349823,
				"z": -.0001803556369850412
			},
			{
				"x": .6250996589660645,
				"y": .6586247682571411,
				"z": -.0001785515050869435
			}
		]],
		"faceBlendshapes": [{
			"categories": [
				{
					"index": 0,
					"score": 5187174338061595e-21,
					"categoryName": "_neutral",
					"displayName": ""
				},
				{
					"index": 1,
					"score": .24521504342556,
					"categoryName": "browDownLeft",
					"displayName": ""
				},
				{
					"index": 2,
					"score": .1987743377685547,
					"categoryName": "browDownRight",
					"displayName": ""
				},
				{
					"index": 3,
					"score": .013400448486208916,
					"categoryName": "browInnerUp",
					"displayName": ""
				},
				{
					"index": 4,
					"score": .012361560948193073,
					"categoryName": "browOuterUpLeft",
					"displayName": ""
				},
				{
					"index": 5,
					"score": .019305096939206123,
					"categoryName": "browOuterUpRight",
					"displayName": ""
				},
				{
					"index": 6,
					"score": 28426356948330067e-21,
					"categoryName": "cheekPuff",
					"displayName": ""
				},
				{
					"index": 7,
					"score": 3.4500112633395474e-7,
					"categoryName": "cheekSquintLeft",
					"displayName": ""
				},
				{
					"index": 8,
					"score": 4.83789051486383e-7,
					"categoryName": "cheekSquintRight",
					"displayName": ""
				},
				{
					"index": 9,
					"score": .07650448381900787,
					"categoryName": "eyeBlinkLeft",
					"displayName": ""
				},
				{
					"index": 10,
					"score": .05070012807846069,
					"categoryName": "eyeBlinkRight",
					"displayName": ""
				},
				{
					"index": 11,
					"score": .13978900015354156,
					"categoryName": "eyeLookDownLeft",
					"displayName": ""
				},
				{
					"index": 12,
					"score": .14198613166809082,
					"categoryName": "eyeLookDownRight",
					"displayName": ""
				},
				{
					"index": 13,
					"score": .2177766114473343,
					"categoryName": "eyeLookInLeft",
					"displayName": ""
				},
				{
					"index": 14,
					"score": .014739357866346836,
					"categoryName": "eyeLookInRight",
					"displayName": ""
				},
				{
					"index": 15,
					"score": .02361512929201126,
					"categoryName": "eyeLookOutLeft",
					"displayName": ""
				},
				{
					"index": 16,
					"score": .19679604470729828,
					"categoryName": "eyeLookOutRight",
					"displayName": ""
				},
				{
					"index": 17,
					"score": .04874616861343384,
					"categoryName": "eyeLookUpLeft",
					"displayName": ""
				},
				{
					"index": 18,
					"score": .049392376095056534,
					"categoryName": "eyeLookUpRight",
					"displayName": ""
				},
				{
					"index": 19,
					"score": .34944331645965576,
					"categoryName": "eyeSquintLeft",
					"displayName": ""
				},
				{
					"index": 20,
					"score": .2939716875553131,
					"categoryName": "eyeSquintRight",
					"displayName": ""
				},
				{
					"index": 21,
					"score": .005955042317509651,
					"categoryName": "eyeWideLeft",
					"displayName": ""
				},
				{
					"index": 22,
					"score": .006776117719709873,
					"categoryName": "eyeWideRight",
					"displayName": ""
				},
				{
					"index": 23,
					"score": 16942436559475027e-21,
					"categoryName": "jawForward",
					"displayName": ""
				},
				{
					"index": 24,
					"score": .0045165494084358215,
					"categoryName": "jawLeft",
					"displayName": ""
				},
				{
					"index": 25,
					"score": .07803940027952194,
					"categoryName": "jawOpen",
					"displayName": ""
				},
				{
					"index": 26,
					"score": 2090057751047425e-20,
					"categoryName": "jawRight",
					"displayName": ""
				},
				{
					"index": 27,
					"score": .06032035872340202,
					"categoryName": "mouthClose",
					"displayName": ""
				},
				{
					"index": 28,
					"score": .00228882092051208,
					"categoryName": "mouthDimpleLeft",
					"displayName": ""
				},
				{
					"index": 29,
					"score": .00781762320548296,
					"categoryName": "mouthDimpleRight",
					"displayName": ""
				},
				{
					"index": 30,
					"score": .0017093931091949344,
					"categoryName": "mouthFrownLeft",
					"displayName": ""
				},
				{
					"index": 31,
					"score": .0019319106359034777,
					"categoryName": "mouthFrownRight",
					"displayName": ""
				},
				{
					"index": 32,
					"score": 8485237776767462e-20,
					"categoryName": "mouthFunnel",
					"displayName": ""
				},
				{
					"index": 33,
					"score": .0009051355300471187,
					"categoryName": "mouthLeft",
					"displayName": ""
				},
				{
					"index": 34,
					"score": .0003630454302765429,
					"categoryName": "mouthLowerDownLeft",
					"displayName": ""
				},
				{
					"index": 35,
					"score": .00017601238505449146,
					"categoryName": "mouthLowerDownRight",
					"displayName": ""
				},
				{
					"index": 36,
					"score": .12865161895751953,
					"categoryName": "mouthPressLeft",
					"displayName": ""
				},
				{
					"index": 37,
					"score": .20137207210063934,
					"categoryName": "mouthPressRight",
					"displayName": ""
				},
				{
					"index": 38,
					"score": .0022203284315764904,
					"categoryName": "mouthPucker",
					"displayName": ""
				},
				{
					"index": 39,
					"score": .0009096377179957926,
					"categoryName": "mouthRight",
					"displayName": ""
				},
				{
					"index": 40,
					"score": .34189721941947937,
					"categoryName": "mouthRollLower",
					"displayName": ""
				},
				{
					"index": 41,
					"score": .11409689486026764,
					"categoryName": "mouthRollUpper",
					"displayName": ""
				},
				{
					"index": 42,
					"score": .17172536253929138,
					"categoryName": "mouthShrugLower",
					"displayName": ""
				},
				{
					"index": 43,
					"score": .004038424696773291,
					"categoryName": "mouthShrugUpper",
					"displayName": ""
				},
				{
					"index": 44,
					"score": .00023205230536404997,
					"categoryName": "mouthSmileLeft",
					"displayName": ""
				},
				{
					"index": 45,
					"score": .00019313619122840464,
					"categoryName": "mouthSmileRight",
					"displayName": ""
				},
				{
					"index": 46,
					"score": .0018571305554360151,
					"categoryName": "mouthStretchLeft",
					"displayName": ""
				},
				{
					"index": 47,
					"score": .0023813238367438316,
					"categoryName": "mouthStretchRight",
					"displayName": ""
				},
				{
					"index": 48,
					"score": 24323100660694763e-21,
					"categoryName": "mouthUpperUpLeft",
					"displayName": ""
				},
				{
					"index": 49,
					"score": 3161552012898028e-20,
					"categoryName": "mouthUpperUpRight",
					"displayName": ""
				},
				{
					"index": 50,
					"score": 1.08198406678639e-7,
					"categoryName": "noseSneerLeft",
					"displayName": ""
				},
				{
					"index": 51,
					"score": 12652527630052646e-22,
					"categoryName": "noseSneerRight",
					"displayName": ""
				}
			],
			"headIndex": -1,
			"headName": ""
		}],
		"facialTransformationMatrixes": [{
			"rows": 4,
			"columns": 4,
			"data": [
				.9947517514228821,
				.10230544209480286,
				.0013679931871592999,
				0,
				-.10230997204780579,
				.9947447776794434,
				.003816320328041911,
				0,
				-.000970348424743861,
				-.0039362297393381596,
				.9999914169311523,
				0,
				2.8888821601867676,
				-7.808934211730957,
				-30.52109146118164,
				1
			]
		}]
	}
};
//#endregion
//#region node_modules/@react-three/drei/web/FaceLandmarker.js
var FaceLandmarkerContext = /* @__PURE__ */ (0, import_react.createContext)({});
var FaceLandmarkerDefaults = {
	basePath: "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.17/wasm",
	options: {
		baseOptions: {
			modelAssetPath: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task",
			delegate: "GPU"
		},
		runningMode: "VIDEO",
		outputFaceBlendshapes: true,
		outputFacialTransformationMatrixes: true
	}
};
var FaceLandmarker = /*#__PURE__*/ (0, import_react.forwardRef)(({ basePath = FaceLandmarkerDefaults.basePath, options = FaceLandmarkerDefaults.options, children }, fref) => {
	const opts = JSON.stringify(options);
	const faceLandmarker = suspend(async () => {
		const { FilesetResolver, FaceLandmarker } = await import("./vision_bundle-CIcccGj7.js");
		const vision = await FilesetResolver.forVisionTasks(basePath);
		return FaceLandmarker.createFromOptions(vision, options);
	}, [basePath, opts]);
	(0, import_react.useEffect)(() => {
		return () => {
			faceLandmarker?.close();
			clear$1([basePath, opts]);
		};
	}, [
		faceLandmarker,
		basePath,
		opts
	]);
	(0, import_react.useImperativeHandle)(fref, () => faceLandmarker, [faceLandmarker]);
	return /*#__PURE__*/ import_react.createElement(FaceLandmarkerContext.Provider, { value: faceLandmarker }, children);
});
function useFaceLandmarker() {
	return (0, import_react.useContext)(FaceLandmarkerContext);
}
//#endregion
//#region node_modules/@react-three/drei/web/FaceControls.js
function mean(v1, v2) {
	return v1.clone().add(v2).multiplyScalar(.5);
}
function localToLocal(objSrc, v, objDst) {
	const v_world = objSrc.localToWorld(v);
	return objDst.worldToLocal(v_world);
}
var FaceControlsContext = /* @__PURE__ */ (0, import_react.createContext)({});
/**
* The camera follows your face.
*
* Pre-requisite: wrap into a `FaceLandmarker` provider:
*
* ```jsx
* ...
* ```
*/
var FaceControls = /* @__PURE__ */ (0, import_react.forwardRef)(({ camera, videoTexture = { start: true }, manualDetect = false, faceLandmarkerResult, manualUpdate = false, makeDefault, smoothTime = .25, offset = true, offsetScalar = 80, eyes = false, eyesAsOrigin = true, depth = .15, debug = false, facemesh }, fref) => {
	var _result$facialTransfo, _result$faceBlendshap;
	const scene = useThree((state) => state.scene);
	const defaultCamera = useThree((state) => state.camera);
	const set = useThree((state) => state.set);
	const get = useThree((state) => state.get);
	const explCamera = camera || defaultCamera;
	const facemeshApiRef = (0, import_react.useRef)(null);
	const [target] = (0, import_react.useState)(() => new Object3D());
	const [irisRightDirPos] = (0, import_react.useState)(() => new Vector3());
	const [irisLeftDirPos] = (0, import_react.useState)(() => new Vector3());
	const [irisRightLookAt] = (0, import_react.useState)(() => new Vector3());
	const [irisLeftLookAt] = (0, import_react.useState)(() => new Vector3());
	const computeTarget = (0, import_react.useCallback)(() => {
		target.parent = explCamera.parent;
		const facemeshApi = facemeshApiRef.current;
		if (facemeshApi) {
			const { outerRef, eyeRightRef, eyeLeftRef } = facemeshApi;
			if (eyeRightRef.current && eyeLeftRef.current) {
				const { irisDirRef: irisRightDirRef } = eyeRightRef.current;
				const { irisDirRef: irisLeftDirRef } = eyeLeftRef.current;
				if (irisRightDirRef.current && irisLeftDirRef.current && outerRef.current) {
					irisRightDirPos.copy(localToLocal(irisRightDirRef.current, new Vector3(0, 0, 0), outerRef.current));
					irisLeftDirPos.copy(localToLocal(irisLeftDirRef.current, new Vector3(0, 0, 0), outerRef.current));
					target.position.copy(localToLocal(outerRef.current, mean(irisRightDirPos, irisLeftDirPos), explCamera.parent || scene));
					irisRightLookAt.copy(localToLocal(irisRightDirRef.current, new Vector3(0, 0, 1), outerRef.current));
					irisLeftLookAt.copy(localToLocal(irisLeftDirRef.current, new Vector3(0, 0, 1), outerRef.current));
					target.lookAt(outerRef.current.localToWorld(mean(irisRightLookAt, irisLeftLookAt)));
				}
			} else if (outerRef.current) {
				target.position.copy(localToLocal(outerRef.current, new Vector3(0, 0, 0), explCamera.parent || scene));
				target.lookAt(outerRef.current.localToWorld(new Vector3(0, 0, 1)));
			}
		}
		return target;
	}, [
		explCamera,
		irisLeftDirPos,
		irisLeftLookAt,
		irisRightDirPos,
		irisRightLookAt,
		scene,
		target
	]);
	const [current] = (0, import_react.useState)(() => new Object3D());
	const update = (0, import_react.useCallback)(function(delta, target) {
		if (explCamera) {
			var _target;
			(_target = target) !== null && _target !== void 0 || (target = computeTarget());
			if (smoothTime > 0) {
				const eps = 1e-9;
				easing.damp3(current.position, target.position, smoothTime, delta, void 0, void 0, eps);
				easing.dampE(current.rotation, target.rotation, smoothTime, delta, void 0, void 0, eps);
			} else {
				current.position.copy(target.position);
				current.rotation.copy(target.rotation);
			}
			explCamera.position.copy(current.position);
			explCamera.rotation.copy(current.rotation);
		}
	}, [
		explCamera,
		computeTarget,
		smoothTime,
		current.position,
		current.rotation
	]);
	useFrame((_, delta) => {
		if (manualUpdate) return;
		update(delta);
	});
	const videoTextureRef = (0, import_react.useRef)(null);
	const [_faceLandmarkerResult, setFaceLandmarkerResult] = (0, import_react.useState)();
	const faceLandmarker = useFaceLandmarker();
	const onVideoFrame = (0, import_react.useCallback)((now, metadata) => {
		const texture = videoTextureRef.current;
		if (!texture) return;
		const videoFrame = texture.source.data;
		setFaceLandmarkerResult(faceLandmarker == null ? void 0 : faceLandmarker.detectForVideo(videoFrame, now));
	}, [faceLandmarker]);
	const api = (0, import_react.useMemo)(() => Object.assign(Object.create(EventDispatcher$2.prototype), {
		computeTarget,
		update,
		facemeshApiRef
	}), [computeTarget, update]);
	(0, import_react.useImperativeHandle)(fref, () => api, [api]);
	(0, import_react.useEffect)(() => {
		if (makeDefault) {
			const old = get().controls;
			set({ controls: api });
			return () => set({ controls: old });
		}
	}, [
		makeDefault,
		api,
		get,
		set
	]);
	const result = faceLandmarkerResult !== null && faceLandmarkerResult !== void 0 ? faceLandmarkerResult : _faceLandmarkerResult;
	const points = result == null ? void 0 : result.faceLandmarks[0];
	const facialTransformationMatrix = result == null || (_result$facialTransfo = result.facialTransformationMatrixes) == null ? void 0 : _result$facialTransfo[0];
	const faceBlendshapes = result == null || (_result$faceBlendshap = result.faceBlendshapes) == null ? void 0 : _result$faceBlendshap[0];
	const videoTextureProps = {
		onVideoFrame,
		...videoTexture
	};
	return /*#__PURE__*/ import_react.createElement(FaceControlsContext.Provider, { value: api }, !manualDetect && /*#__PURE__*/ import_react.createElement(import_react.Suspense, { fallback: null }, "src" in videoTextureProps ? /*#__PURE__*/ import_react.createElement(VideoTexture, _extends$1({ ref: videoTextureRef }, videoTextureProps)) : /*#__PURE__*/ import_react.createElement(WebcamVideoTexture, _extends$1({ ref: videoTextureRef }, videoTextureProps))), /*#__PURE__*/ import_react.createElement(Facemesh, _extends$1({
		ref: facemeshApiRef,
		children: /*#__PURE__*/ import_react.createElement("meshNormalMaterial", { side: 2 })
	}, facemesh, {
		points,
		depth,
		facialTransformationMatrix,
		faceBlendshapes,
		eyes,
		eyesAsOrigin,
		offset,
		offsetScalar,
		debug,
		"rotation-z": Math.PI,
		visible: debug
	})));
});
var useFaceControls = () => (0, import_react.useContext)(FaceControlsContext);
//#endregion
export { AccumulativeShadows, AdaptiveDpr, AdaptiveEvents, ArcballControls, AsciiRenderer, BBAnchor, Backdrop, BakeShadows, Billboard, Bounds, Box, Bvh, CameraControls, CameraControls$1 as CameraControlsImpl, CameraShake, Capsule, CatmullRomLine, Caustics, Center, Circle, Clone, Cloud, CloudInstance, Clouds, ComputedAttribute, Cone, ContactShadows, CubeCamera, CubeTexture, CubicBezierLine, CurveModifier, CycleRaycast, Cylinder, Decal, Detailed, DetectGPU, DeviceOrientationControls, Dodecahedron, DragControls, Edges, Effects, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, Example, Extrude, FaceControls, FaceLandmarker, FaceLandmarkerDefaults, Facemesh, FacemeshDatas, FacemeshEye, FacemeshEyeDefaults, Fbo, Fbx, FirstPersonControls, Fisheye, Float, FlyControls, GizmoHelper, GizmoViewcube, GizmoViewport, Gltf, GradientTexture, GradientType, Grid, Helper, Html, Hud, Icosahedron, Image$1 as Image, Instance, InstancedAttribute, Instances, IsObject, KeyboardControls, Ktx2, Lathe, Lightformer, Line, Loader, MapControls, MarchingCube, MarchingCubes, MarchingPlane, Mask, MatcapTexture, Merged, MeshDiscardMaterial, MeshDistortMaterial, MeshPortalMaterial, MeshReflectorMaterial, MeshRefractionMaterial, MeshTransmissionMaterial, MeshWobbleMaterial, MotionPathControls, MultiMaterial, NormalTexture, Octahedron, OrbitControls, OrthographicCamera, Outlines, PerformanceMonitor, PerspectiveCamera, PivotControls, Plane, Point, PointMaterial, PointMaterialImpl, PointerLockControls, Points, PointsBuffer, Polyhedron, PositionMesh, PositionPoint, PositionalAudio, Preload, PresentationControls, Progress, QuadraticBezierLine, RandomizedLight, RenderCubeTexture, RenderTexture, Resize, Ring, RoundedBox, RoundedBoxGeometry, Sampler, ScreenQuad, ScreenSizer, ScreenSpace, ScreenVideoTexture, Scroll, ScrollControls, Segment, SegmentObject, Segments, Select, Shadow, ShadowAlpha, Shape, Sky, SoftShadows, Sparkles, Sphere, Splat, SpotLight, SpotLightShadow, SpriteAnimator, Stage, Stars, Stats, StatsGl, Svg, Tetrahedron, Text, Text3D, Texture, Torus, TorusKnot, TrackballControls, Trail, TrailTexture, TransformControls, Tube, VideoTexture, View, WebcamVideoTexture, Wireframe, accumulativeContext, calcPosFromAngles, calculateScaleFactor, checkIfFrameIsEmpty, createInstances, getFirstFrame, isWebGL2Available, meshBounds, shaderMaterial, useAnimations, useAspect, useBVH, useBounds, useBoxProjectedEnv, useCamera, useContextBridge, useCubeCamera, useCubeTexture, useCursor, useDepthBuffer, useDetectGPU, useEnvironment, useFBO, useFBX, useFaceControls, useFaceLandmarker, useFont, useGLTF, useGizmoContext, useHelper, useIntersect, useKTX2, useKeyboardControls, useMask, useMatcapTexture, useMotion, useNormalTexture, usePerformanceMonitor, useProgress, useScroll, useSelect, useSpriteAnimator, useSpriteLoader, useSurfaceSampler, useTexture, useTrail, useTrailTexture, useVideoTexture };

//# sourceMappingURL=@react-three_drei.js.map