Przeglądaj źródła

[ts][threejs] Add support for lighting and shadow. Upgraded three to 0.162.0. Added new constructor.

Davide Tantillo 9 miesięcy temu
rodzic
commit
7594c959dc
35 zmienionych plików z 6886 dodań i 1752 usunięć
  1. 5 0
      examples/export/runtimes.sh
  2. 3 0
      spine-ts/index.html
  3. 516 8
      spine-ts/package-lock.json
  4. 8 9
      spine-ts/package.json
  5. 0 1248
      spine-ts/spine-threejs/example/OrbitalControls.js
  6. 19 0
      spine-ts/spine-threejs/example/assets/coin-pma.atlas
  7. BIN
      spine-ts/spine-threejs/example/assets/coin-pma.png
  8. 259 0
      spine-ts/spine-threejs/example/assets/coin-pro.json
  9. 101 0
      spine-ts/spine-threejs/example/assets/raptor-pma.atlas
  10. BIN
      spine-ts/spine-threejs/example/assets/raptor-pma.png
  11. 95 0
      spine-ts/spine-threejs/example/assets/spineboy-pma.atlas
  12. BIN
      spine-ts/spine-threejs/example/assets/spineboy-pma.png
  13. 557 0
      spine-ts/spine-threejs/example/assets/spineboy-pro.json
  14. BIN
      spine-ts/spine-threejs/example/assets/spineboy-pro.skel
  15. 94 0
      spine-ts/spine-threejs/example/assets/spineboy.atlas
  16. BIN
      spine-ts/spine-threejs/example/assets/spineboy.png
  17. 141 137
      spine-ts/spine-threejs/example/coordinate-transform.html
  18. 84 79
      spine-ts/spine-threejs/example/index.html
  19. 42 31
      spine-ts/spine-threejs/example/logarithmic-depth-buffer.html
  20. 138 122
      spine-ts/spine-threejs/example/physics.html
  21. 276 0
      spine-ts/spine-threejs/example/shadows.html
  22. 6 0
      spine-ts/spine-threejs/example/typescript/README.md
  23. 716 0
      spine-ts/spine-threejs/example/typescript/assets/raptor-pro.json
  24. 93 0
      spine-ts/spine-threejs/example/typescript/assets/raptor.atlas
  25. BIN
      spine-ts/spine-threejs/example/typescript/assets/raptor.png
  26. 12 0
      spine-ts/spine-threejs/example/typescript/index.html
  27. 135 0
      spine-ts/spine-threejs/example/typescript/index.ts
  28. 3168 0
      spine-ts/spine-threejs/example/typescript/package-lock.json
  29. 20 0
      spine-ts/spine-threejs/example/typescript/package.json
  30. 6 0
      spine-ts/spine-threejs/package.json
  31. 226 34
      spine-ts/spine-threejs/src/MeshBatcher.ts
  32. 143 78
      spine-ts/spine-threejs/src/SkeletonMesh.ts
  33. 19 3
      spine-ts/spine-threejs/src/ThreeJsTexture.ts
  34. 1 0
      spine-ts/spine-threejs/src/require-shim.ts
  35. 3 3
      spine-ts/spine-threejs/tsconfig.json

+ 5 - 0
examples/export/runtimes.sh

@@ -500,6 +500,11 @@ rm "$ROOT/spine-ts/spine-threejs/example/assets/"*
 cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-ts/spine-threejs/example/assets/"
 cp -f ../raptor/export/raptor.atlas "$ROOT/spine-ts/spine-threejs/example/assets/"
 cp -f ../raptor/export/raptor.png "$ROOT/spine-ts/spine-threejs/example/assets/"
+
+cp -f ../coin/export/coin-pro.json "$ROOT/spine-ts/spine-threejs/example/assets/"
+cp -f ../coin/export/coin-pma.atlas "$ROOT/spine-ts/spine-threejs/example/assets/"
+cp -f ../coin/export/coin-pma.png "$ROOT/spine-ts/spine-threejs/example/assets/"
+
 cp -f ../celestial-circus/export/* "$ROOT/spine-ts/spine-threejs/example/assets/"
 
 rm "$ROOT/spine-ts/spine-player/example/assets/"*

+ 3 - 0
spine-ts/index.html

@@ -217,6 +217,9 @@
         <li>
           <a href="/spine-threejs/example/physics.html">Physics</a>
         </li>
+        <li>
+          <a href="/spine-threejs/example/shadows.html">Shadows</a>
+        </li>
       </ul>
     </ul>
   </div>

Plik diff jest za duży
+ 516 - 8
spine-ts/package-lock.json


Plik diff jest za duży
+ 8 - 9
spine-ts/package.json


+ 0 - 1248
spine-ts/spine-threejs/example/OrbitalControls.js

@@ -1,1248 +0,0 @@
-let EventDispatcher = THREE.EventDispatcher;
-let MOUSE = THREE.MOUSE;
-let Quaternion = THREE.Quaternion;
-let Spherical = THREE.Spherical;
-let TOUCH = THREE.TOUCH;
-let Vector2 = THREE.Vector2;
-let Vector3 = THREE.Vector3;
-
-// This set of controls performs orbiting, dollying (zooming), and panning.
-// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
-//
-//    Orbit - left mouse / touch: one-finger move
-//    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
-//    Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
-
-const _changeEvent = { type: 'change' };
-const _startEvent = { type: 'start' };
-const _endEvent = { type: 'end' };
-
-class OrbitControls extends EventDispatcher {
-
-	constructor(object, domElement) {
-
-		super();
-
-		if (domElement === undefined) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
-		if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
-
-		this.object = object;
-		this.domElement = domElement;
-		this.domElement.style.touchAction = 'none'; // disable touch scroll
-
-		// Set to false to disable this control
-		this.enabled = true;
-
-		// "target" sets the location of focus, where the object orbits around
-		this.target = new Vector3();
-
-		// How far you can dolly in and out ( PerspectiveCamera only )
-		this.minDistance = 0;
-		this.maxDistance = Infinity;
-
-		// How far you can zoom in and out ( OrthographicCamera only )
-		this.minZoom = 0;
-		this.maxZoom = Infinity;
-
-		// How far you can orbit vertically, upper and lower limits.
-		// Range is 0 to Math.PI radians.
-		this.minPolarAngle = 0; // radians
-		this.maxPolarAngle = Math.PI; // radians
-
-		// How far you can orbit horizontally, upper and lower limits.
-		// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )
-		this.minAzimuthAngle = - Infinity; // radians
-		this.maxAzimuthAngle = Infinity; // radians
-
-		// Set to true to enable damping (inertia)
-		// If damping is enabled, you must call controls.update() in your animation loop
-		this.enableDamping = false;
-		this.dampingFactor = 0.05;
-
-		// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
-		// Set to false to disable zooming
-		this.enableZoom = true;
-		this.zoomSpeed = 1.0;
-
-		// Set to false to disable rotating
-		this.enableRotate = true;
-		this.rotateSpeed = 1.0;
-
-		// Set to false to disable panning
-		this.enablePan = true;
-		this.panSpeed = 1.0;
-		this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up
-		this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
-
-		// Set to true to automatically rotate around the target
-		// If auto-rotate is enabled, you must call controls.update() in your animation loop
-		this.autoRotate = false;
-		this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60
-
-		// The four arrow keys
-		this.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };
-
-		// Mouse buttons
-		this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
-
-		// Touch fingers
-		this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
-
-		// for reset
-		this.target0 = this.target.clone();
-		this.position0 = this.object.position.clone();
-		this.zoom0 = this.object.zoom;
-
-		// the target DOM element for key events
-		this._domElementKeyEvents = null;
-
-		//
-		// public methods
-		//
-
-		this.getPolarAngle = function () {
-
-			return spherical.phi;
-
-		};
-
-		this.getAzimuthalAngle = function () {
-
-			return spherical.theta;
-
-		};
-
-		this.getDistance = function () {
-
-			return this.object.position.distanceTo(this.target);
-
-		};
-
-		this.listenToKeyEvents = function (domElement) {
-
-			domElement.addEventListener('keydown', onKeyDown);
-			this._domElementKeyEvents = domElement;
-
-		};
-
-		this.saveState = function () {
-
-			scope.target0.copy(scope.target);
-			scope.position0.copy(scope.object.position);
-			scope.zoom0 = scope.object.zoom;
-
-		};
-
-		this.reset = function () {
-
-			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 method is exposed, but perhaps it would be better if we can make it private...
-		this.update = function () {
-
-			const offset = new Vector3();
-
-			// so camera.up is the orbit axis
-			const quat = new Quaternion().setFromUnitVectors(object.up, new Vector3(0, 1, 0));
-			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;
-
-				offset.copy(position).sub(scope.target);
-
-				// rotate offset to "y-axis-is-up" space
-				offset.applyQuaternion(quat);
-
-				// angle from z-axis around y-axis
-				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;
-
-				}
-
-				// restrict theta to be between desired limits
-
-				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);
-
-					}
-
-				}
-
-				// restrict phi to be between desired limits
-				spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
-
-				spherical.makeSafe();
-
-
-				spherical.radius *= scale;
-
-				// restrict radius to be between desired limits
-				spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
-
-				// move target to panned location
-
-				if (scope.enableDamping === true) {
-
-					scope.target.addScaledVector(panOffset, scope.dampingFactor);
-
-				} else {
-
-					scope.target.add(panOffset);
-
-				}
-
-				offset.setFromSpherical(spherical);
-
-				// rotate offset back to "camera-up-vector-is-up" space
-				offset.applyQuaternion(quatInverse);
-
-				position.copy(scope.target).add(offset);
-
-				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);
-
-				}
-
-				scale = 1;
-
-				// update condition is:
-				// min(camera displacement, camera rotation in radians)^2 > EPS
-				// using small-angle approximation cos(x/2) = 1 - x^2 / 8
-
-				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.dispose = function () {
-
-			scope.domElement.removeEventListener('contextmenu', onContextMenu);
-
-			scope.domElement.removeEventListener('pointerdown', onPointerDown);
-			scope.domElement.removeEventListener('pointercancel', onPointerCancel);
-			scope.domElement.removeEventListener('wheel', onMouseWheel);
-
-			scope.domElement.removeEventListener('pointermove', onPointerMove);
-			scope.domElement.removeEventListener('pointerup', onPointerUp);
-
-
-			if (scope._domElementKeyEvents !== null) {
-
-				scope._domElementKeyEvents.removeEventListener('keydown', onKeyDown);
-
-			}
-
-			//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
-
-		};
-
-		//
-		// internals
-		//
-
-		const scope = this;
-
-		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 = 0.000001;
-
-		// current position in spherical coordinates
-		const spherical = new Spherical();
-		const sphericalDelta = new Spherical();
-
-		let scale = 1;
-		const panOffset = new Vector3();
-		let zoomChanged = false;
-
-		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 pointers = [];
-		const pointerPositions = {};
-
-		function getAutoRotationAngle() {
-
-			return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
-
-		}
-
-		function getZoomScale() {
-
-			return Math.pow(0.95, scope.zoomSpeed);
-
-		}
-
-		function rotateLeft(angle) {
-
-			sphericalDelta.theta -= angle;
-
-		}
-
-		function rotateUp(angle) {
-
-			sphericalDelta.phi -= angle;
-
-		}
-
-		const panLeft = function () {
-
-			const v = new Vector3();
-
-			return function panLeft(distance, objectMatrix) {
-
-				v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
-				v.multiplyScalar(- distance);
-
-				panOffset.add(v);
-
-			};
-
-		}();
-
-		const panUp = function () {
-
-			const v = new Vector3();
-
-			return function panUp(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);
-
-			};
-
-		}();
-
-		// deltaX and deltaY are in pixels; right and down are positive
-		const pan = function () {
-
-			const offset = new Vector3();
-
-			return function pan(deltaX, deltaY) {
-
-				const element = scope.domElement;
-
-				if (scope.object.isPerspectiveCamera) {
-
-					// perspective
-					const position = scope.object.position;
-					offset.copy(position).sub(scope.target);
-					let targetDistance = offset.length();
-
-					// half of the fov is center to top of screen
-					targetDistance *= Math.tan((scope.object.fov / 2) * Math.PI / 180.0);
-
-					// we use only clientHeight here so aspect ratio does not distort speed
-					panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
-					panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
-
-				} else if (scope.object.isOrthographicCamera) {
-
-					// orthographic
-					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 {
-
-					// camera neither orthographic nor perspective
-					console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.');
-					scope.enablePan = false;
-
-				}
-
-			};
-
-		}();
-
-		function dollyOut(dollyScale) {
-
-			if (scope.object.isPerspectiveCamera) {
-
-				scale /= dollyScale;
-
-			} else if (scope.object.isOrthographicCamera) {
-
-				scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
-				scope.object.updateProjectionMatrix();
-				zoomChanged = true;
-
-			} else {
-
-				console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
-				scope.enableZoom = false;
-
-			}
-
-		}
-
-		function dollyIn(dollyScale) {
-
-			if (scope.object.isPerspectiveCamera) {
-
-				scale *= dollyScale;
-
-			} else if (scope.object.isOrthographicCamera) {
-
-				scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
-				scope.object.updateProjectionMatrix();
-				zoomChanged = true;
-
-			} else {
-
-				console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
-				scope.enableZoom = false;
-
-			}
-
-		}
-
-		//
-		// event callbacks - update the object state
-		//
-
-		function handleMouseDownRotate(event) {
-
-			rotateStart.set(event.clientX, event.clientY);
-
-		}
-
-		function handleMouseDownDolly(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;
-
-			rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height
-
-			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) {
-
-			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) {
-
-				// prevent the browser from scrolling on cursor keys
-				event.preventDefault();
-
-				scope.update();
-
-			}
-
-
-		}
-
-		function handleTouchStartRotate() {
-
-			if (pointers.length === 1) {
-
-				rotateStart.set(pointers[0].pageX, pointers[0].pageY);
-
-			} else {
-
-				const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
-				const y = 0.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 = 0.5 * (pointers[0].pageX + pointers[1].pageX);
-				const y = 0.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 = 0.5 * (event.pageX + position.x);
-				const y = 0.5 * (event.pageY + position.y);
-
-				rotateEnd.set(x, y);
-
-			}
-
-			rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
-
-			const element = scope.domElement;
-
-			rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height
-
-			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 = 0.5 * (event.pageX + position.x);
-				const y = 0.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);
-
-		}
-
-		//
-		// event handlers - FSM: listen for events and reset state
-		//
-
-		function onPointerDown(event) {
-
-			if (scope.enabled === false) return;
-
-			if (pointers.length === 0) {
-
-				scope.domElement.setPointerCapture(event.pointerId);
-
-				scope.domElement.addEventListener('pointermove', onPointerMove);
-				scope.domElement.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) {
-
-			removePointer(event);
-
-			if (pointers.length === 0) {
-
-				scope.domElement.releasePointerCapture(event.pointerId);
-
-				scope.domElement.removeEventListener('pointermove', onPointerMove);
-				scope.domElement.removeEventListener('pointerup', onPointerUp);
-
-			}
-
-			scope.dispatchEvent(_endEvent);
-
-			state = STATE.NONE;
-
-		}
-
-		function onPointerCancel(event) {
-
-			removePointer(event);
-
-		}
-
-		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) 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 === undefined) {
-
-				position = new Vector2();
-				pointerPositions[event.pointerId] = position;
-
-			}
-
-			position.set(event.pageX, event.pageY);
-
-		}
-
-		function getSecondPointerPosition(event) {
-
-			const pointer = (event.pointerId === pointers[0].pointerId) ? pointers[1] : pointers[0];
-
-			return pointerPositions[pointer.pointerId];
-
-		}
-
-		//
-
-		scope.domElement.addEventListener('contextmenu', onContextMenu);
-
-		scope.domElement.addEventListener('pointerdown', onPointerDown);
-		scope.domElement.addEventListener('pointercancel', onPointerCancel);
-		scope.domElement.addEventListener('wheel', onMouseWheel, { passive: false });
-
-		// force an update at start
-
-		this.update();
-
-	}
-
-}
-
-
-// This set of controls performs orbiting, dollying (zooming), and panning.
-// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
-// This is very similar to OrbitControls, another set of touch behavior
-//
-//    Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
-//    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
-//    Pan - left mouse, or arrow keys / touch: one-finger move
-
-class MapControls extends OrbitControls {
-
-	constructor(object, domElement) {
-
-		super(object, domElement);
-
-		this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up
-
-		this.mouseButtons.LEFT = MOUSE.PAN;
-		this.mouseButtons.RIGHT = MOUSE.ROTATE;
-
-		this.touches.ONE = TOUCH.PAN;
-		this.touches.TWO = TOUCH.DOLLY_ROTATE;
-
-	}
-
-}

+ 19 - 0
spine-ts/spine-threejs/example/assets/coin-pma.atlas

@@ -0,0 +1,19 @@
+coin-pma.png
+	size: 1024, 1024
+	filter: Linear, Linear
+	pma: true
+coin-front-logo
+	bounds: 2, 609, 305, 302
+coin-front-shine-logo
+	bounds: 309, 629, 282, 282
+coin-front-shine-spineboy
+	bounds: 2, 21, 282, 282
+coin-front-spineboy
+	bounds: 2, 305, 305, 302
+coin-side-round
+	bounds: 309, 345, 144, 282
+coin-side-straight
+	bounds: 2, 2, 17, 282
+	rotate: 90
+shine
+	bounds: 593, 666, 72, 245

BIN
spine-ts/spine-threejs/example/assets/coin-pma.png


+ 259 - 0
spine-ts/spine-threejs/example/assets/coin-pro.json

@@ -0,0 +1,259 @@
+{
+"skeleton": {
+	"hash": "fKr+fe4rKEk",
+	"spine": "4.2.22",
+	"x": -152.5,
+	"y": -151,
+	"width": 305,
+	"height": 302,
+	"images": "./images/",
+	"audio": ""
+},
+"bones": [
+	{ "name": "root" },
+	{ "name": "coin-front", "parent": "root" },
+	{ "name": "clipping", "parent": "coin-front" },
+	{ "name": "coin-sides", "parent": "root" },
+	{ "name": "coin-side-round", "parent": "coin-sides" },
+	{ "name": "coin-side-straight", "parent": "coin-sides" },
+	{ "name": "shine", "parent": "root", "x": 243.14 }
+],
+"slots": [
+	{ "name": "coin-side", "bone": "coin-side-straight", "color": "ffdb2fff", "attachment": "coin-side-straight" },
+	{ "name": "coin-side-round", "bone": "coin-side-round", "color": "ffdb2fff", "attachment": "coin-side-round" },
+	{ "name": "coin-front-texture", "bone": "coin-front", "color": "868686ff", "attachment": "coin-front-logo" },
+	{ "name": "coin-front-shine", "bone": "coin-front", "color": "888888ff", "dark": "000000", "attachment": "coin-front-shine-logo", "blend": "additive" },
+	{ "name": "clipping", "bone": "clipping", "attachment": "clipping" },
+	{ "name": "shine", "bone": "shine", "color": "ffffff60", "attachment": "shine", "blend": "additive" }
+],
+"skins": [
+	{
+		"name": "default",
+		"attachments": {
+			"clipping": {
+				"clipping": {
+					"type": "clipping",
+					"end": "clipping",
+					"vertexCount": 39,
+					"vertices": [ 0.1, 140.26, -26.4, 138.14, -50.51, 131.25, -75.42, 119.06, -98.21, 101.04, -115.44, 82.22, -127.63, 62.08, -136.11, 39.03, -140.08, 19.68, -141.41, -0.19, -140.08, -22.98, -134.78, -45.5, -125.24, -66.44, -113.32, -84.19, -98.21, -101.95, -80.46, -116.52, -61.38, -127.39, -38.92, -134.81, -18.22, -139.27, -0.14, -140.58, 24.23, -138.48, 45.45, -132.46, 67.98, -122.5, 86.58, -110.19, 102.56, -95.25, 115.4, -78.75, 125.36, -61.72, 134, -42.33, 138.46, -22.15, 139.24, -0.15, 138.46, 20.29, 133.48, 39.94, 127.19, 58.54, 117.5, 76.1, 104.4, 92.86, 88.42, 108.32, 69.03, 121.42, 50.43, 130.85, 26.32, 137.4 ],
+					"color": "ce3a3aff"
+				}
+			},
+			"coin-front-shine": {
+				"coin-front-shine-logo": { "width": 282, "height": 282 },
+				"coin-front-shine-spineboy": { "width": 282, "height": 282 }
+			},
+			"coin-front-texture": {
+				"coin-front-logo": { "width": 305, "height": 302 },
+				"coin-front-spineboy": { "width": 305, "height": 302 }
+			},
+			"coin-side": {
+				"coin-side-straight": { "x": 0.5, "width": 17, "height": 282 }
+			},
+			"coin-side-round": {
+				"coin-side-round": { "x": -69.43, "width": 144, "height": 282 }
+			},
+			"shine": {
+				"shine": { "y": 0.5, "scaleX": 1.6004, "scaleY": 1.6004, "width": 72, "height": 245 }
+			}
+		}
+	}
+],
+"animations": {
+	"animation": {
+		"slots": {
+			"coin-front-shine": {
+				"rgba2": [
+					{ "light": "7d7d7dff", "dark": "000000" },
+					{ "time": 0.2667, "light": "000000ff", "dark": "7e7e7e" },
+					{ "time": 0.664, "light": "000000ff", "dark": "000000" },
+					{ "time": 1.0333, "light": "7f7f7fff", "dark": "000000" },
+					{ "time": 1.3333, "light": "404040ff", "dark": "000000" },
+					{ "time": 1.6, "light": "000000ff", "dark": "7e7e7e" },
+					{ "time": 2.0022, "light": "000000ff", "dark": "000000" },
+					{ "time": 2.4, "light": "7f7f7fff", "dark": "000000" },
+					{ "time": 2.6667, "light": "7d7d7dff", "dark": "000000" }
+				],
+				"attachment": [
+					{ "time": 0.6667, "name": "coin-front-shine-spineboy" },
+					{ "time": 2, "name": "coin-front-shine-logo" }
+				]
+			},
+			"coin-front-texture": {
+				"rgba": [
+					{ "color": "858585ff" },
+					{ "time": 0.4, "color": "ffffffff" },
+					{
+						"time": 0.6696,
+						"color": "858585ff",
+						"curve": [ 0.725, 0.59, 0.892, 1, 0.725, 0.59, 0.892, 1, 0.725, 0.59, 0.892, 1, 0.725, 1, 0.892, 1 ]
+					},
+					{ "time": 0.9667, "color": "ffffffff" },
+					{ "time": 1.3318, "color": "858585ff", "curve": "stepped" },
+					{ "time": 1.3333, "color": "858585ff" },
+					{ "time": 1.7333, "color": "ffffffff" },
+					{ "time": 1.9982, "color": "858585ff", "curve": "stepped" },
+					{ "time": 2.0022, "color": "858585ff" },
+					{ "time": 2.3, "color": "ffffffff" },
+					{ "time": 2.6667, "color": "858585ff" }
+				],
+				"attachment": [
+					{ "time": 0.6667, "name": "coin-front-spineboy" },
+					{ "time": 2, "name": "coin-front-logo" }
+				]
+			}
+		},
+		"bones": {
+			"coin-front": {
+				"translate": [
+					{},
+					{ "time": 0.664, "x": 8.3, "curve": "stepped" },
+					{
+						"time": 0.6696,
+						"x": -8.3,
+						"curve": [ 0.794, -7.08, 1.167, 0, 0.794, 0, 1.167, 0 ]
+					},
+					{ "time": 1.3333 },
+					{ "time": 1.9982, "x": 8.3, "curve": "stepped" },
+					{ "time": 2.0022, "x": -8.3 },
+					{ "time": 2.6667 }
+				],
+				"scale": [
+					{
+						"curve": [ 0.164, 1, 0.484, 0.091, 0.164, 1, 0.484, 1 ]
+					},
+					{ "time": 0.664, "x": 0, "curve": "stepped" },
+					{
+						"time": 0.6696,
+						"x": 0.003,
+						"curve": [ 0.786, 0.153, 1.167, 1, 0.786, 1, 1.167, 1 ]
+					},
+					{
+						"time": 1.3333,
+						"curve": [ 1.442, 0.992, 1.858, 0.098, 1.442, 1, 1.858, 1 ]
+					},
+					{ "time": 1.9982, "x": 0.003, "curve": "stepped" },
+					{
+						"time": 2.0022,
+						"x": 0.003,
+						"curve": [ 2.123, 0.151, 2.501, 1, 2.123, 1, 2.501, 1 ]
+					},
+					{ "time": 2.6667 }
+				]
+			},
+			"coin-side-round": {
+				"translate": [
+					{},
+					{ "time": 0.664, "x": -6.75, "curve": "stepped" },
+					{
+						"time": 0.6696,
+						"x": 7.03,
+						"curve": [ 0.794, 5.99, 1.167, 0, 0.794, 0, 1.167, 0 ]
+					},
+					{ "time": 1.3333 },
+					{ "time": 1.9982, "x": -6.75, "curve": "stepped" },
+					{ "time": 2.0022, "x": 7.03 },
+					{ "time": 2.6667 }
+				],
+				"scale": [
+					{
+						"curve": [ 0.085, 1, 0.207, 0.789, 0.085, 1, 0.207, 1 ]
+					},
+					{
+						"time": 0.3333,
+						"x": 0.555,
+						"curve": [ 0.449, 0.347, 0.567, 0.122, 0.449, 1, 0.567, 1 ]
+					},
+					{ "time": 0.664, "x": 0.014, "curve": "stepped" },
+					{
+						"time": 0.6696,
+						"x": -0.028,
+						"curve": [ 0.723, -0.126, 0.865, -0.367, 0.723, 1, 0.865, 1 ]
+					},
+					{
+						"time": 1,
+						"x": -0.609,
+						"curve": [ 1.053, -0.778, 1.29, -0.997, 1.053, 1, 1.29, 1 ]
+					},
+					{ "time": 1.3318, "x": -1, "curve": "stepped" },
+					{
+						"time": 1.3333,
+						"curve": [ 1.384, 0.997, 1.439, 0.94, 1.384, 1, 1.439, 1 ]
+					},
+					{
+						"time": 1.5,
+						"x": 0.852,
+						"curve": [ 1.564, 0.748, 1.703, 0.509, 1.564, 1, 1.703, 1 ]
+					},
+					{
+						"time": 1.8,
+						"x": 0.315,
+						"curve": [ 1.873, 0.13, 1.987, 0.015, 1.873, 1, 1.987, 1 ]
+					},
+					{ "time": 1.9982, "x": 0.014, "curve": "stepped" },
+					{
+						"time": 2.0022,
+						"x": -0.028,
+						"curve": [ 2.039, -0.072, 2.123, -0.239, 2.039, 1, 2.123, 1 ]
+					},
+					{
+						"time": 2.2018,
+						"x": -0.365,
+						"curve": [ 2.269, -0.513, 2.337, -0.635, 2.269, 1, 2.337, 1 ]
+					},
+					{
+						"time": 2.4,
+						"x": -0.731,
+						"curve": [ 2.503, -0.871, 2.596, -0.961, 2.503, 1, 2.596, 1 ]
+					},
+					{
+						"time": 2.6592,
+						"x": -1,
+						"curve": [ 2.661, -1, 2.665, 1, 2.661, 1, 2.665, 1 ]
+					},
+					{ "time": 2.6667 }
+				]
+			},
+			"shine": {
+				"translate": [
+					{
+						"curve": [ 0.167, 0, 0.5, -473.39, 0.167, 0, 0.5, 0 ]
+					},
+					{
+						"time": 0.6667,
+						"x": -473.39,
+						"curve": [ 0.833, -473.39, 1.167, -33.16, 0.833, 0, 1.167, 0 ]
+					},
+					{
+						"time": 1.3333,
+						"x": -33.16,
+						"curve": [ 1.5, -33.16, 1.833, -473.39, 1.5, 0, 1.833, 0 ]
+					},
+					{
+						"time": 2,
+						"x": -473.39,
+						"curve": [ 2.167, -473.39, 2.5, 0, 2.167, 0, 2.5, 0 ]
+					},
+					{ "time": 2.6667 }
+				]
+			}
+		},
+		"drawOrder": [
+			{
+				"time": 0.6667,
+				"offsets": [
+					{ "slot": "coin-side", "offset": 2 }
+				]
+			},
+			{ "time": 0.6696 },
+			{
+				"time": 1.9982,
+				"offsets": [
+					{ "slot": "coin-side", "offset": 2 }
+				]
+			},
+			{ "time": 2.0022 }
+		]
+	}
+}
+}

+ 101 - 0
spine-ts/spine-threejs/example/assets/raptor-pma.atlas

@@ -0,0 +1,101 @@
+raptor-pma.png
+	size: 1024, 512
+	filter: Linear, Linear
+	pma: true
+	scale: 0.5
+back-arm
+	bounds: 829, 88, 46, 25
+	rotate: 90
+back-bracer
+	bounds: 195, 238, 39, 28
+	rotate: 90
+back-hand
+	bounds: 724, 140, 36, 34
+	rotate: 90
+back-knee
+	bounds: 760, 131, 49, 67
+	rotate: 90
+back-thigh
+	bounds: 225, 238, 39, 24
+	rotate: 90
+eyes-open
+	bounds: 975, 204, 47, 45
+front-arm
+	bounds: 969, 112, 48, 26
+front-bracer
+	bounds: 724, 97, 41, 29
+	rotate: 90
+front-hand
+	bounds: 251, 239, 41, 38
+front-open-hand
+	bounds: 856, 76, 43, 44
+	rotate: 90
+front-thigh
+	bounds: 729, 178, 57, 29
+	rotate: 90
+gun
+	bounds: 894, 251, 107, 103
+gun-nohand
+	bounds: 764, 241, 105, 102
+head
+	bounds: 756, 345, 136, 149
+lower-leg
+	bounds: 475, 237, 73, 98
+	rotate: 90
+mouth-grind
+	bounds: 975, 172, 47, 30
+mouth-smile
+	bounds: 975, 140, 47, 30
+neck
+	bounds: 366, 282, 18, 21
+raptor-back-arm
+	bounds: 636, 97, 82, 86
+	rotate: 90
+raptor-body
+	bounds: 2, 2, 632, 233
+raptor-front-arm
+	bounds: 871, 168, 81, 102
+	rotate: 90
+raptor-front-leg
+	bounds: 2, 237, 191, 257
+raptor-hindleg-back
+	bounds: 195, 279, 169, 215
+raptor-horn
+	bounds: 431, 312, 182, 80
+	rotate: 90
+raptor-horn-back
+	bounds: 513, 318, 176, 77
+	rotate: 90
+raptor-jaw
+	bounds: 894, 356, 126, 138
+raptor-jaw-tooth
+	bounds: 294, 240, 37, 48
+	rotate: 90
+raptor-mouth-inside
+	bounds: 344, 241, 36, 41
+	rotate: 90
+raptor-saddle-strap-back
+	bounds: 575, 242, 54, 74
+raptor-saddle-strap-front
+	bounds: 764, 182, 57, 95
+	rotate: 90
+raptor-saddle-w-shadow
+	bounds: 592, 323, 162, 171
+raptor-tail-shadow
+	bounds: 366, 305, 189, 63
+	rotate: 90
+raptor-tongue
+	bounds: 387, 239, 86, 64
+stirrup-back
+	bounds: 829, 136, 44, 35
+	rotate: 90
+stirrup-front
+	bounds: 866, 121, 45, 50
+	rotate: 90
+stirrup-strap
+	bounds: 918, 120, 49, 46
+torso
+	bounds: 636, 181, 54, 91
+	rotate: 90
+visor
+	bounds: 631, 237, 131, 84

BIN
spine-ts/spine-threejs/example/assets/raptor-pma.png


+ 95 - 0
spine-ts/spine-threejs/example/assets/spineboy-pma.atlas

@@ -0,0 +1,95 @@
+spineboy-pma.png
+	size: 1024, 256
+	filter: Linear, Linear
+	pma: true
+	scale: 0.5
+crosshair
+	bounds: 352, 7, 45, 45
+eye-indifferent
+	bounds: 862, 105, 47, 45
+eye-surprised
+	bounds: 505, 79, 47, 45
+front-bracer
+	bounds: 826, 66, 29, 40
+front-fist-closed
+	bounds: 786, 65, 38, 41
+front-fist-open
+	bounds: 710, 51, 43, 44
+	rotate: 90
+front-foot
+	bounds: 210, 6, 63, 35
+front-shin
+	bounds: 665, 128, 41, 92
+	rotate: 90
+front-thigh
+	bounds: 2, 2, 23, 56
+	rotate: 90
+front-upper-arm
+	bounds: 250, 205, 23, 49
+goggles
+	bounds: 665, 171, 131, 83
+gun
+	bounds: 798, 152, 105, 102
+head
+	bounds: 2, 27, 136, 149
+hoverboard-board
+	bounds: 2, 178, 246, 76
+hoverboard-thruster
+	bounds: 722, 96, 30, 32
+	rotate: 90
+hoverglow-small
+	bounds: 275, 81, 137, 38
+mouth-grind
+	bounds: 614, 97, 47, 30
+mouth-oooo
+	bounds: 612, 65, 47, 30
+mouth-smile
+	bounds: 661, 64, 47, 30
+muzzle-glow
+	bounds: 382, 54, 25, 25
+muzzle-ring
+	bounds: 275, 54, 25, 105
+	rotate: 90
+muzzle01
+	bounds: 911, 95, 67, 40
+	rotate: 90
+muzzle02
+	bounds: 792, 108, 68, 42
+muzzle03
+	bounds: 956, 171, 83, 53
+	rotate: 90
+muzzle04
+	bounds: 275, 7, 75, 45
+muzzle05
+	bounds: 140, 3, 68, 38
+neck
+	bounds: 250, 182, 18, 21
+portal-bg
+	bounds: 140, 43, 133, 133
+portal-flare1
+	bounds: 554, 65, 56, 30
+portal-flare2
+	bounds: 759, 112, 57, 31
+	rotate: 90
+portal-flare3
+	bounds: 554, 97, 58, 30
+portal-shade
+	bounds: 275, 121, 133, 133
+portal-streaks1
+	bounds: 410, 126, 126, 128
+portal-streaks2
+	bounds: 538, 129, 125, 125
+rear-bracer
+	bounds: 857, 67, 28, 36
+rear-foot
+	bounds: 663, 96, 57, 30
+rear-shin
+	bounds: 414, 86, 38, 89
+	rotate: 90
+rear-thigh
+	bounds: 756, 63, 28, 47
+rear-upper-arm
+	bounds: 60, 5, 20, 44
+	rotate: 90
+torso
+	bounds: 905, 164, 49, 90

BIN
spine-ts/spine-threejs/example/assets/spineboy-pma.png


Plik diff jest za duży
+ 557 - 0
spine-ts/spine-threejs/example/assets/spineboy-pro.json


BIN
spine-ts/spine-threejs/example/assets/spineboy-pro.skel


+ 94 - 0
spine-ts/spine-threejs/example/assets/spineboy.atlas

@@ -0,0 +1,94 @@
+spineboy.png
+	size: 1024, 256
+	filter: Linear, Linear
+	scale: 0.5
+crosshair
+	bounds: 352, 7, 45, 45
+eye-indifferent
+	bounds: 862, 105, 47, 45
+eye-surprised
+	bounds: 505, 79, 47, 45
+front-bracer
+	bounds: 826, 66, 29, 40
+front-fist-closed
+	bounds: 786, 65, 38, 41
+front-fist-open
+	bounds: 710, 51, 43, 44
+	rotate: 90
+front-foot
+	bounds: 210, 6, 63, 35
+front-shin
+	bounds: 665, 128, 41, 92
+	rotate: 90
+front-thigh
+	bounds: 2, 2, 23, 56
+	rotate: 90
+front-upper-arm
+	bounds: 250, 205, 23, 49
+goggles
+	bounds: 665, 171, 131, 83
+gun
+	bounds: 798, 152, 105, 102
+head
+	bounds: 2, 27, 136, 149
+hoverboard-board
+	bounds: 2, 178, 246, 76
+hoverboard-thruster
+	bounds: 722, 96, 30, 32
+	rotate: 90
+hoverglow-small
+	bounds: 275, 81, 137, 38
+mouth-grind
+	bounds: 614, 97, 47, 30
+mouth-oooo
+	bounds: 612, 65, 47, 30
+mouth-smile
+	bounds: 661, 64, 47, 30
+muzzle-glow
+	bounds: 382, 54, 25, 25
+muzzle-ring
+	bounds: 275, 54, 25, 105
+	rotate: 90
+muzzle01
+	bounds: 911, 95, 67, 40
+	rotate: 90
+muzzle02
+	bounds: 792, 108, 68, 42
+muzzle03
+	bounds: 956, 171, 83, 53
+	rotate: 90
+muzzle04
+	bounds: 275, 7, 75, 45
+muzzle05
+	bounds: 140, 3, 68, 38
+neck
+	bounds: 250, 182, 18, 21
+portal-bg
+	bounds: 140, 43, 133, 133
+portal-flare1
+	bounds: 554, 65, 56, 30
+portal-flare2
+	bounds: 759, 112, 57, 31
+	rotate: 90
+portal-flare3
+	bounds: 554, 97, 58, 30
+portal-shade
+	bounds: 275, 121, 133, 133
+portal-streaks1
+	bounds: 410, 126, 126, 128
+portal-streaks2
+	bounds: 538, 129, 125, 125
+rear-bracer
+	bounds: 857, 67, 28, 36
+rear-foot
+	bounds: 663, 96, 57, 30
+rear-shin
+	bounds: 414, 86, 38, 89
+	rotate: 90
+rear-thigh
+	bounds: 756, 63, 28, 47
+rear-upper-arm
+	bounds: 60, 5, 20, 44
+	rotate: 90
+torso
+	bounds: 905, 164, 49, 90

BIN
spine-ts/spine-threejs/example/assets/spineboy.png


+ 141 - 137
spine-ts/spine-threejs/example/coordinate-transform.html

@@ -1,155 +1,159 @@
 <html>
+  <head>
+	<meta charset="UTF-8" />
+    <title>spine-threejs</title>
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+
+      body,
+      html {
+        height: 100%;
+      }
+
+      canvas {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+
+    <script type="importmap">
+    {
+        "imports": {
+            "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
+            "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
+            "spine-threejs": "../dist/esm/spine-threejs.mjs"
+        }
+    }
+    </script>
+  </head>
+
+  <body>
+    <script type="module">
+		import * as THREE from "three";
+		import * as spine from "spine-threejs";
+		import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
+
+      	let scene, camera, renderer;
+		let skeletonMesh, atlas, atlasLoader, geometry, material, cube, tailBone;
+		let assetManager;
+		let canvas;
+		let controls;
+		let lastFrameTime = Date.now() / 1000;
+
+		let baseUrl = "assets/";
+		let skeletonFile = "raptor-pro.json";
+		let atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
+		let animation = "walk";
+
+		function init() {
+			// create the THREE.JS camera, scene and renderer (WebGL)
+			let width = window.innerWidth, height = window.innerHeight;
+			camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
+			camera.position.y = 200;
+			camera.position.z = 800;
+			scene = new THREE.Scene();
+			renderer = new THREE.WebGLRenderer();
+			renderer.setSize(width, height);
+			document.body.appendChild(renderer.domElement);
+			canvas = renderer.domElement;
+			controls = new OrbitControls(camera, renderer.domElement);
+
+			// load the assets required to display the Raptor model
+			assetManager = new spine.AssetManager(baseUrl);
+			assetManager.loadText(skeletonFile);
+			assetManager.loadTextureAtlas(atlasFile);
+
+			requestAnimationFrame(load);
+		}
+
+		function load(name, scale) {
+			if (assetManager.isLoadingComplete()) {
+				// Load the texture atlas using name.atlas and name.png from the AssetManager.
+				// The function passed to TextureAtlas is used to resolve relative paths.
+				atlas = assetManager.require(atlasFile);
+
+				// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+				atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+
+				// Create a SkeletonJson instance for parsing the .json file.
+				let skeletonJson = new spine.SkeletonJson(atlasLoader);
+
+				// Set the scale to apply during parsing, parse the file, and create a new skeleton.
+				skeletonJson.scale = 0.4;
+				let skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
+
+				// Create a SkeletonMesh from the data and attach it to the scene
+				skeletonMesh = new spine.SkeletonMesh({ skeletonData });
+				skeletonMesh.state.setAnimation(0, animation, true);
+				skeletonMesh.position.x = 120;
+				skeletonMesh.position.y = -20;
+				skeletonMesh.position.z = 10;
+				scene.add(skeletonMesh);
+
+				// Add a wireframe cube which will be positioned at the tail bone
+				geometry = new THREE.BoxGeometry(20, 20, 20);
+				material = new THREE.MeshBasicMaterial({ color: 0xff00, wireframe: true });
+				cube = new THREE.Mesh(geometry, material);
+				scene.add(cube);
+
+				// Get the tail bone
+				tailBone = skeletonMesh.skeleton.findBone("tail10");
 
-<head>
-	<meta charset="UTF-8">
-	<title>spine-threejs</title>
-	<script src="https://unpkg.com/[email protected]/build/three.js"></script>
-	<script src="../dist/iife/spine-threejs.js"></script>
-	<script src="./OrbitalControls.js"></script>
-</head>
-<style>
-	* {
-		margin: 0;
-		padding: 0;
-	}
-
-	body,
-	html {
-		height: 100%
-	}
-
-	canvas {
-		position: absolute;
-		width: 100%;
-		height: 100%;
-	}
-</style>
-
-<body>
-	<script>
-		(function () {
-			let scene, camera, renderer;
-			let skeletonMesh, cube, tailBone;
-			let assetManager;
-			let canvas;
-			let controls;
-			let lastFrameTime = Date.now() / 1000;
-
-			let baseUrl = "assets/";
-			let skeletonFile = "raptor-pro.json";
-			let atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
-			let animation = "walk";
-
-			function init() {
-				// create the THREE.JS camera, scene and renderer (WebGL)
-				let width = window.innerWidth, height = window.innerHeight;
-				camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
-				camera.position.y = 200;
-				camera.position.z = 800;
-				scene = new THREE.Scene();
-				renderer = new THREE.WebGLRenderer();
-				renderer.setSize(width, height);
-				document.body.appendChild(renderer.domElement);
-				canvas = renderer.domElement;
-				controls = new OrbitControls(camera, renderer.domElement);
-
-				// load the assets required to display the Raptor model
-				assetManager = new spine.AssetManager(baseUrl);
-				assetManager.loadText(skeletonFile);
-				assetManager.loadTextureAtlas(atlasFile);
-
-				requestAnimationFrame(load);
-			}
-
-			function load(name, scale) {
-				if (assetManager.isLoadingComplete()) {
-					// Load the texture atlas using name.atlas and name.png from the AssetManager.
-					// The function passed to TextureAtlas is used to resolve relative paths.
-					atlas = assetManager.require(atlasFile);
-
-					// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
-					atlasLoader = new spine.AtlasAttachmentLoader(atlas);
-
-					// Create a SkeletonJson instance for parsing the .json file.
-					let skeletonJson = new spine.SkeletonJson(atlasLoader);
-
-					// Set the scale to apply during parsing, parse the file, and create a new skeleton.
-					skeletonJson.scale = 0.4;
-					let skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
-
-					// Create a SkeletonMesh from the data and attach it to the scene
-					skeletonMesh = new spine.SkeletonMesh(skeletonData, (parameters) => {
-						parameters.depthTest = true;
-						parameters.depthWrite = true;
-						parameters.alphaTest = 0.001;
-					});
-					skeletonMesh.state.setAnimation(0, animation, true);
-                    skeletonMesh.position.x = 120;
-                    skeletonMesh.position.y = -20;
-                    skeletonMesh.position.z = 10;
-					scene.add(skeletonMesh);
-
-                    // Add a wireframe cube which will be positioned at the tail bone
-                    geometry = new THREE.BoxGeometry(20, 20, 20);
-                    material = new THREE.MeshBasicMaterial({ color: 0xff00, wireframe: true });
-                    cube = new THREE.Mesh(geometry, material);
-                    scene.add(cube);
-
-                    // Get the tail bone
-                    tailBone = skeletonMesh.skeleton.findBone("tail10");
+				requestAnimationFrame(render);
+			} else requestAnimationFrame(load);
+		}
 
-					requestAnimationFrame(render);
-				} else requestAnimationFrame(load);
-			}            
+		let lastTime = Date.now();
+		function render() {
+			// calculate delta time for animation purposes
+			let now = Date.now() / 1000;
+			let delta = now - lastFrameTime;
+			lastFrameTime = now;
 
-			let lastTime = Date.now();
-			function render() {
-				// calculate delta time for animation purposes
-				let now = Date.now() / 1000;
-				let delta = now - lastFrameTime;
-				lastFrameTime = now;
+			// resize canvas to use full page, adjust camera/renderer
+			resize();
 
-				// resize canvas to use full page, adjust camera/renderer
-				resize();
+			// Update orbital controls
+			controls.update();
 
-				// Update orbital controls
-				controls.update();
+			// update the animation
+			skeletonMesh.update(delta);
 
-				// update the animation
-				skeletonMesh.update(delta);
+			// Get the tail bone coordinates in the skeleton's local coordinate space.
+			let position = new THREE.Vector3(tailBone.worldX, tailBone.worldY, 0);
 
-                // Get the tail bone coordinates in the skeleton's local coordinate space.
-                let position = new THREE.Vector3(tailBone.worldX, tailBone.worldY, 0);
+			// Convert the tail bone coordinates to world coordinates.
+			skeletonMesh.localToWorld(position)
 
-                // Convert the tail bone coordinates to world coordinates.
-                skeletonMesh.localToWorld(position)
+			// Set the tail bone coordinates as the cube's position.
+			cube.position.set(position.x, position.y, position.z);
 
-                // Set the tail bone coordinates as the cube's position.
-                cube.position.set(position.x, position.y, position.z);
+			// render the scene
+			renderer.render(scene, camera);
 
-				// render the scene
-				renderer.render(scene, camera);
+			requestAnimationFrame(render);
+		}
 
-				requestAnimationFrame(render);
+		function resize() {
+			let w = window.innerWidth;
+			let h = window.innerHeight;
+			if (canvas.width != w || canvas.height != h) {
+				canvas.width = w;
+				canvas.height = h;
 			}
 
-			function resize() {
-				let w = window.innerWidth;
-				let h = window.innerHeight;
-				if (canvas.width != w || canvas.height != h) {
-					canvas.width = w;
-					canvas.height = h;
-				}
-
-				camera.aspect = w / h;
-				camera.updateProjectionMatrix();
+			camera.aspect = w / h;
+			camera.updateProjectionMatrix();
 
-				renderer.setSize(w, h);
-			}
+			renderer.setSize(w, h);
+		}
 
-			init();
-		}());
-	</script>
-</body>
+		init();
 
+    </script>
+  </body>
 </html>

+ 84 - 79
spine-ts/spine-threejs/example/index.html

@@ -2,50 +2,62 @@
   <head>
     <meta charset="UTF-8" />
     <title>spine-threejs</title>
-    <script src="https://unpkg.com/[email protected]/build/three.js"></script>
-    <script src="../dist/iife/spine-threejs.js"></script>
-    <script src="./OrbitalControls.js"></script>
-  </head>
-  <style>
-    * {
-      margin: 0;
-      padding: 0;
-    }
-
-    body,
-    html {
-      height: 100%;
-    }
-
-    canvas {
-      position: absolute;
-      width: 100%;
-      height: 100%;
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+
+      body,
+      html {
+        height: 100%;
+      }
+
+      canvas {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+
+    <script type="importmap">
+    {
+        "imports": {
+            "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
+            "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
+            "spine-threejs": "../dist/esm/spine-threejs.mjs"
+        }
     }
-  </style>
+    </script>
+  </head>
 
   <body>
-    <script>
-      (function () {
-        let scene, camera, renderer;
-        let geometry, material, mesh, skeletonMesh;
-        let assetManager;
-        let canvas;
-        let controls;
-        let lastFrameTime = Date.now() / 1000;
-
-        let baseUrl = "assets/";
-        let skeletonFile = "raptor-pro.json";
-        let atlasFile = skeletonFile
+    <script type="module">
+      import * as THREE from "three";
+      import * as spine from "spine-threejs";
+      import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
+
+      let scene, camera, renderer;
+      let geometry, material, mesh, skeletonMesh;
+      let atlas;
+      let atlasLoader;
+      let assetManager;
+      let canvas;
+      let controls;
+      let lastFrameTime = Date.now() / 1000;
+
+      let baseUrl = "assets/";
+      let skeletonFile = "raptor-pro.json";
+      let atlasFile = skeletonFile
           .replace("-pro", "")
           .replace("-ess", "")
           .replace(".json", ".atlas");
-        let animation = "walk";
+      let animation = "walk";
 
-        function init() {
+      function init() {
           // create the THREE.JS camera, scene and renderer (WebGL)
           let width = window.innerWidth,
-            height = window.innerHeight;
+          height = window.innerHeight;
           camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
           camera.position.y = 100;
           camera.position.z = 400;
@@ -62,53 +74,46 @@
           assetManager.loadTextureAtlas(atlasFile);
 
           requestAnimationFrame(load);
-        }
+      }
 
-        function load(name, scale) {
+      function load(name, scale) {
           if (assetManager.isLoadingComplete()) {
-            // Add a box to the scene to which we attach the skeleton mesh
-            geometry = new THREE.BoxGeometry(200, 200, 200);
-            material = new THREE.MeshBasicMaterial({
+          // Add a box to the scene to which we attach the skeleton mesh
+          geometry = new THREE.BoxGeometry(200, 200, 200);
+          material = new THREE.MeshBasicMaterial({
               color: 0xff0000,
               wireframe: true,
-            });
-            mesh = new THREE.Mesh(geometry, material);
-            scene.add(mesh);
+          });
+          mesh = new THREE.Mesh(geometry, material);
+          scene.add(mesh);
 
-            // Load the texture atlas using name.atlas and name.png from the AssetManager.
-            // The function passed to TextureAtlas is used to resolve relative paths.
-            atlas = assetManager.require(atlasFile);
+          // Load the texture atlas using name.atlas and name.png from the AssetManager.
+          // The function passed to TextureAtlas is used to resolve relative paths.
+          atlas = assetManager.require(atlasFile);
 
-            // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
-            atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+          // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+          atlasLoader = new spine.AtlasAttachmentLoader(atlas);
 
-            // Create a SkeletonJson instance for parsing the .json file.
-            let skeletonJson = new spine.SkeletonJson(atlasLoader);
+          // Create a SkeletonJson instance for parsing the .json file.
+          let skeletonJson = new spine.SkeletonJson(atlasLoader);
 
-            // Set the scale to apply during parsing, parse the file, and create a new skeleton.
-            skeletonJson.scale = 0.4;
-            let skeletonData = skeletonJson.readSkeletonData(
+          // Set the scale to apply during parsing, parse the file, and create a new skeleton.
+          skeletonJson.scale = 0.4;
+          let skeletonData = skeletonJson.readSkeletonData(
               assetManager.require(skeletonFile)
-            );
-
-            // Create a SkeletonMesh from the data and attach it to the scene
-            skeletonMesh = new spine.SkeletonMesh(
-              skeletonData,
-              (parameters) => {
-                parameters.depthTest = true;
-                parameters.depthWrite = true;
-                parameters.alphaTest = 0.001;
-              }
-            );
-            skeletonMesh.state.setAnimation(0, animation, true);
-            mesh.add(skeletonMesh);
-
-            requestAnimationFrame(render);
+          );
+
+          // Create a SkeletonMesh from the data and attach it to the scene
+          skeletonMesh = new spine.SkeletonMesh({ skeletonData });
+          skeletonMesh.state.setAnimation(0, animation, true);
+          mesh.add(skeletonMesh);
+
+          requestAnimationFrame(render);
           } else requestAnimationFrame(load);
-        }
+      }
 
-        let lastTime = Date.now();
-        function render() {
+      let lastTime = Date.now();
+      function render() {
           // calculate delta time for animation purposes
           let now = Date.now() / 1000;
           let delta = now - lastFrameTime;
@@ -127,24 +132,24 @@
           renderer.render(scene, camera);
 
           requestAnimationFrame(render);
-        }
+      }
 
-        function resize() {
+      function resize() {
           let w = window.innerWidth;
           let h = window.innerHeight;
           if (canvas.width != w || canvas.height != h) {
-            canvas.width = w;
-            canvas.height = h;
+          canvas.width = w;
+          canvas.height = h;
           }
 
           camera.aspect = w / h;
           camera.updateProjectionMatrix();
 
           renderer.setSize(w, h);
-        }
+      }
+
+      init();
 
-        init();
-      })();
     </script>
   </body>
-</html>
+</html>

+ 42 - 31
spine-ts/spine-threejs/example/logarithmic-depth-buffer.html

@@ -2,33 +2,43 @@
   <head>
     <meta charset="UTF-8" />
     <title>spine-threejs</title>
-    <script src="https://unpkg.com/[email protected]/build/three.js"></script>
-    <script src="../dist/iife/spine-threejs.js"></script>
-    <script src="./OrbitalControls.js"></script>
-  </head>
-  <style>
-    * {
-      margin: 0;
-      padding: 0;
-    }
-
-    body,
-    html {
-      height: 100%;
-    }
-
-    canvas {
-      position: absolute;
-      width: 100%;
-      height: 100%;
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+
+      body,
+      html {
+        height: 100%;
+      }
+
+      canvas {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+
+    <script type="importmap">
+    {
+        "imports": {
+            "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
+            "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
+            "spine-threejs": "../dist/esm/spine-threejs.mjs"
+        }
     }
-  </style>
+    </script>
+  </head>
 
   <body>
-    <script>
-      (function () {
-        let scene, camera, renderer;
-        let geometry, material, mesh, skeletonMesh;
+    <script type="module">
+      import * as THREE from "three";
+      import * as spine from "spine-threejs";
+      import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
+
+      let scene, camera, renderer;
+        let geometry, material, mesh, skeletonMesh, atlas, atlasLoader;
         let assetManager;
         let canvas;
         let controls;
@@ -95,11 +105,10 @@
             // Provide a custom vertex/fragment shader pair that supports
             // the logarithmic depth buffer.
             // See https://discourse.threejs.org/t/shadermaterial-render-order-with-logarithmicdepthbuffer-is-wrong/49221/3
-            skeletonMesh = new spine.SkeletonMesh(
+            skeletonMesh = new spine.SkeletonMesh({
               skeletonData,
-              (materialParameters) => {
+              materialFactory: (materialParameters) => {
                 materialParameters.vertexShader = `
-                attribute vec4 color;
                 varying vec2 vUv;
                 varying vec4 vColor;
 
@@ -130,12 +139,14 @@
 
                   gl_FragColor = texture2D(map, vUv)*vColor;
                   #ifdef USE_SPINE_ALPHATEST
-                  if (gl_FragColor.a < alphaTest) discard;
+                    if (gl_FragColor.a < alphaTest) discard;
                   #endif
                 }
                 `;
+
+                return new spine.SkeletonMeshMaterial(materialParameters);
               }
-            );
+            });
             skeletonMesh.state.setAnimation(0, animation, true);
             mesh.add(skeletonMesh);
 
@@ -180,7 +191,7 @@
         }
 
         init();
-      })();
+
     </script>
   </body>
-</html>
+</html>

+ 138 - 122
spine-ts/spine-threejs/example/physics.html

@@ -2,149 +2,165 @@
   <head>
     <meta charset="UTF-8" />
     <title>spine-threejs</title>
-    <script src="https://unpkg.com/[email protected]/build/three.js"></script>
-    <script src="../dist/iife/spine-threejs.js"></script>
-    <script src="./OrbitalControls.js"></script>
-  </head>
-  <style>
-    * {
-      margin: 0;
-      padding: 0;
-    }
-
-    body,
-    html {
-      height: 100%;
-    }
-
-    canvas {
-      position: absolute;
-      width: 100%;
-      height: 100%;
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+
+      body,
+      html {
+        height: 100%;
+      }
+
+      canvas {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+
+    <script type="importmap">
+    {
+        "imports": {
+            "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
+            "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
+            "spine-threejs": "../dist/esm/spine-threejs.mjs"
+        }
     }
-  </style>
+    </script>
+  </head>
 
   <body>
-    <script>
-      (function () {
-        let scene, camera, renderer;
-        let geometry, material, mesh, skeletonMesh;
-        let assetManager;
-        let canvas;
-        let controls;
-        let lastFrameTime = Date.now() / 1000;
-
-        let pma = false;
-        let baseUrl = "assets/";
-        let skeletonFile = "celestial-circus-pro.json";
-        let atlasFile = `celestial-circus${pma ? "-pma" : ""}.atlas`;
-
-        function init() {
-          // create the THREE.JS camera, scene and renderer (WebGL)
-          let width = window.innerWidth,
-            height = window.innerHeight;
-          camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
-          camera.position.y = 0;
-          camera.position.z = 800;
-          scene = new THREE.Scene();
-          renderer = new THREE.WebGLRenderer();
-          renderer.setSize(width, height);
-          document.body.appendChild(renderer.domElement);
-          canvas = renderer.domElement;
-          controls = new OrbitControls(camera, renderer.domElement);
-
-          // load the assets required to display the Raptor model
-          assetManager = new spine.AssetManager(baseUrl, undefined, pma);
-          assetManager.loadText(skeletonFile);
-          assetManager.loadTextureAtlas(atlasFile);
-
-          requestAnimationFrame(load);
-        }
-
-        function load(name, scale) {
-          if (assetManager.isLoadingComplete()) {
-            // Add a box to the scene to which we attach the skeleton mesh
-            geometry = new THREE.BoxGeometry(200, 200, 200);
-            material = new THREE.MeshBasicMaterial({
-              color: 0xff0000,
-              wireframe: true,
-            });
-            mesh = new THREE.Mesh(geometry, material);
-            scene.add(mesh);
-
-            // Load the texture atlas using name.atlas and name.png from the AssetManager.
-            // The function passed to TextureAtlas is used to resolve relative paths.
-            atlas = assetManager.require(atlasFile);
-
-            // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
-            atlasLoader = new spine.AtlasAttachmentLoader(atlas);
-
-            // Create a SkeletonJson instance for parsing the .json file.
-            let skeletonJson = new spine.SkeletonJson(atlasLoader);
-
-            // Set the scale to apply during parsing, parse the file, and create a new skeleton.
-            skeletonJson.scale = 0.4;
-            let skeletonData = skeletonJson.readSkeletonData(
-              assetManager.require(skeletonFile)
-            );
+    <script type="module">
+      import * as THREE from "three";
+      import * as spine from "spine-threejs";
+      import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
+
+      let scene, camera, renderer;
+      let geometry, material, mesh, skeletonMesh, atlas, atlasLoader;
+      let assetManager;
+      let canvas;
+      let controls;
+      let lastFrameTime = Date.now() / 1000;
+
+      let pma = true;
+      let baseUrl = "assets/";
+      let skeletonFile = "celestial-circus-pro.json";
+      let atlasFile = `celestial-circus${pma ? "-pma" : ""}.atlas`;
+
+      function init() {
+        // create the THREE.JS camera, scene and renderer (WebGL)
+        let width = window.innerWidth,
+          height = window.innerHeight;
+        camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
+        camera.position.y = 0;
+        camera.position.z = 800;
+        scene = new THREE.Scene();
+        renderer = new THREE.WebGLRenderer();
+        renderer.setSize(width, height);
+        document.body.appendChild(renderer.domElement);
+        canvas = renderer.domElement;
+        controls = new OrbitControls(camera, renderer.domElement);
+
+        // load the assets required to display the Raptor model
+        assetManager = new spine.AssetManager(baseUrl, undefined, pma);
+        assetManager.loadText(skeletonFile);
+        assetManager.loadTextureAtlas(atlasFile);
+
+        requestAnimationFrame(load);
+      }
+
+      function load(name, scale) {
+        if (assetManager.isLoadingComplete()) {
+          // Add a box to the scene to which we attach the skeleton mesh
+          geometry = new THREE.BoxGeometry(200, 200, 200);
+          material = new THREE.MeshBasicMaterial({
+            color: 0xff0000,
+            wireframe: true,
+          });
+          mesh = new THREE.Mesh(geometry, material);
+          scene.add(mesh);
+
+          // Load the texture atlas using name.atlas and name.png from the AssetManager.
+          // The function passed to TextureAtlas is used to resolve relative paths.
+          atlas = assetManager.require(atlasFile);
+
+          // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+          atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+
+          // Create a SkeletonJson instance for parsing the .json file.
+          let skeletonJson = new spine.SkeletonJson(atlasLoader);
+
+          // Set the scale to apply during parsing, parse the file, and create a new skeleton.
+          skeletonJson.scale = 0.4;
+          let skeletonData = skeletonJson.readSkeletonData(
+            assetManager.require(skeletonFile)
+          );
 
             // Create a SkeletonMesh from the data and attach it to the scene
-            skeletonMesh = new spine.SkeletonMesh(
+            skeletonMesh = new spine.SkeletonMesh({
               skeletonData,
-              (parameters) => {
-                parameters.depthTest = true;
-                parameters.depthWrite = true;
-                parameters.alphaTest = 0.001;
-              }
-            );
+              materialFactory: (parameters) => {
+                return new THREE.MeshBasicMaterial({
+                  ...parameters,
+                  // transparent: true,
+                  // depthWrite: true,
+                  // depthTest: true,
+                  // alphaTest: 0.001,
+                  // vertexColors: true,
+                });
+              },
+              twoColorTint: false,
+            });
             skeletonMesh.state.setAnimation(0, "swing", true);
             skeletonMesh.state.setAnimation(1, "eyeblink-long", true);
             mesh.add(skeletonMesh);
 
-            skeletonMesh.position.y = -300;
+          skeletonMesh.position.y = -200;
 
-            requestAnimationFrame(render);
-          } else requestAnimationFrame(load);
-        }
+          requestAnimationFrame(render);
+        } else requestAnimationFrame(load);
+      }
 
-        let lastTime = Date.now();
-        function render() {
-          // calculate delta time for animation purposes
-          let now = Date.now() / 1000;
-          let delta = now - lastFrameTime;
-          lastFrameTime = now;
+      let lastTime = Date.now();
+      function render() {
+        // calculate delta time for animation purposes
+        let now = Date.now() / 1000;
+        let delta = now - lastFrameTime;
+        lastFrameTime = now;
 
-          // resize canvas to use full page, adjust camera/renderer
-          resize();
+        // resize canvas to use full page, adjust camera/renderer
+        resize();
 
-          // Update orbital controls
-          controls.update();
+        // Update orbital controls
+        controls.update();
 
-          // update the animation
-          skeletonMesh.update(delta);
+        // update the animation
+        skeletonMesh.update(delta);
 
-          // render the scene
-          renderer.render(scene, camera);
+        // render the scene
+        renderer.render(scene, camera);
 
-          requestAnimationFrame(render);
+        requestAnimationFrame(render);
+      }
+
+      function resize() {
+        let w = window.innerWidth;
+        let h = window.innerHeight;
+        if (canvas.width != w || canvas.height != h) {
+          canvas.width = w;
+          canvas.height = h;
         }
 
-        function resize() {
-          let w = window.innerWidth;
-          let h = window.innerHeight;
-          if (canvas.width != w || canvas.height != h) {
-            canvas.width = w;
-            canvas.height = h;
-          }
+        camera.aspect = w / h;
+        camera.updateProjectionMatrix();
 
-          camera.aspect = w / h;
-          camera.updateProjectionMatrix();
+        renderer.setSize(w, h);
+      }
 
-          renderer.setSize(w, h);
-        }
+      init();
 
-        init();
-      })();
     </script>
   </body>
-</html>
+</html>

+ 276 - 0
spine-ts/spine-threejs/example/shadows.html

@@ -0,0 +1,276 @@
+<html>
+  <head>
+    <meta charset="UTF-8" />
+    <title>spine-threejs</title>
+
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+
+      body,
+      html {
+        height: 100%;
+      }
+
+      canvas {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+
+    <script type="importmap">
+      {
+          "imports": {
+              "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
+              "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
+              "spine-threejs": "../dist/esm/spine-threejs.mjs"
+          }
+      }
+    </script>
+  </head>
+
+  <body>
+    <script type="module">
+      import * as THREE from "three";
+      import * as spine from "spine-threejs";
+      import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
+
+      let scene, camera, renderer;
+      let geometry, material, mesh, skeletonMesh, atlas, atlasLoader, atlas2, atlasLoader2, skeletonMesh2, atlas3, atlasLoader3, skeletonMesh3;
+      let assetManager;
+      let canvas;
+      let controls;
+      let lastFrameTime = Date.now() / 1000;
+
+      let pma = false;
+
+      let baseUrl = "assets/";
+      let skeletonFile = "raptor-pro.json";
+      let atlasFile = "raptor.atlas";
+      let animation = "walk";
+
+      let skeletonFile2 = "celestial-circus-pro.json";
+      let atlasFile2 = "celestial-circus.atlas";
+      let animation2 = "swing";
+
+      let skeletonFile3 = "coin-pro.json";
+      let atlasFile3 = "coin-pma.atlas";
+      let animation3 = "animation";
+
+      function init() {
+        // create the THREE.JS camera, scene and renderer (WebGL)
+        let width = window.innerWidth,
+          height = window.innerHeight;
+        camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
+        camera.position.y = 700;
+        camera.position.z = 300;
+        camera.lookAt(new THREE.Vector3(0, 0, 0))
+        scene = new THREE.Scene();
+        renderer = new THREE.WebGLRenderer({ antialias: true });
+        renderer.setSize(width, height);
+        renderer.shadowMap.enabled = true
+
+        document.body.appendChild(renderer.domElement);
+        canvas = renderer.domElement;
+        controls = new OrbitControls(camera, renderer.domElement);
+
+        // LIGHTS - Ambient
+        const ambientLight = new THREE.AmbientLight(0xffffff, 1.0)
+        scene.add(ambientLight)
+
+        // LIGHTS - spotLight
+        const spotLight = new THREE.SpotLight(0xffffff, 5, 1200, Math.PI / 4, 0, 0)
+        spotLight.position.set(0, 1000, 0)
+        spotLight.castShadow = true
+        spotLight.shadow.mapSize.set(8192, 8192)
+        spotLight.shadow.bias = -0.00001;
+
+        scene.add(spotLight)
+
+        const spotLightHepler = new THREE.SpotLightHelper(spotLight)
+        scene.add(spotLightHepler)
+
+        // BOX
+        const boxGeometry = new THREE.BoxGeometry(400, 10, 10)
+        const boxMaterial = new THREE.MeshStandardMaterial({
+          transparent: true,
+          metalness: 0.5,
+          roughness: 1,
+          opacity: 1,
+        })
+        const box = new THREE.Mesh(boxGeometry, boxMaterial)
+        box.position.set(0, 300, -200)
+        box.castShadow = true
+        box.receiveShadow = true
+        scene.add(box)
+
+        // PLANE
+        const planeGeometry = new THREE.PlaneGeometry(2000, 2000)
+        const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x213573 })
+        const plane = new THREE.Mesh(planeGeometry, planeMaterial)
+        plane.rotation.x = -Math.PI / 2
+        plane.material.side = THREE.DoubleSide
+        plane.receiveShadow = true
+        scene.add(plane)
+
+        // load the assets required to display the Raptor model
+        assetManager = new spine.AssetManager(baseUrl, undefined, pma);
+        assetManager.loadText(skeletonFile);
+        assetManager.loadTextureAtlas(atlasFile);
+
+        assetManager.loadText(skeletonFile2);
+        assetManager.loadTextureAtlas(atlasFile2);
+
+        assetManager.loadText(skeletonFile3);
+        assetManager.loadTextureAtlas(atlasFile3);
+
+        requestAnimationFrame(load);
+      }
+
+      function load(name, scale) {
+        if (assetManager.isLoadingComplete()) {
+
+          // Load the texture atlas using name.atlas and name.png from the AssetManager.
+          // The function passed to TextureAtlas is used to resolve relative paths.
+          atlas = assetManager.require(atlasFile);
+          atlas2 = assetManager.require(atlasFile2);
+          atlas3 = assetManager.require(atlasFile3);
+
+          // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+          atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+          atlasLoader2 = new spine.AtlasAttachmentLoader(atlas2);
+          atlasLoader3 = new spine.AtlasAttachmentLoader(atlas3);
+
+          // Create a SkeletonJson instance for parsing the .json file.
+          let skeletonJson = new spine.SkeletonJson(atlasLoader);
+          let skeletonJson2 = new spine.SkeletonJson(atlasLoader2);
+          let skeletonJson3 = new spine.SkeletonJson(atlasLoader3);
+
+          // Set the scale to apply during parsing, parse the file, and create a new skeleton.
+          skeletonJson.scale = 0.4;
+          let skeletonData = skeletonJson.readSkeletonData(
+            assetManager.require(skeletonFile)
+          );
+          skeletonJson2.scale = 0.4;
+          let skeletonData2 = skeletonJson2.readSkeletonData(
+            assetManager.require(skeletonFile2)
+          );
+
+          skeletonJson3.scale = 0.4;
+          let skeletonData3 = skeletonJson3.readSkeletonData(
+            assetManager.require(skeletonFile3)
+          );
+
+          // Create a SkeletonMesh from the data and attach it to the scene
+          skeletonMesh = new spine.SkeletonMesh({
+            skeletonData,
+            materialFactory: param => {
+              param.alphaTest = 0.001;
+              return new THREE.MeshStandardMaterial(param);
+            }
+          });
+          skeletonMesh.state.setAnimation(0, animation, true);
+          scene.add(skeletonMesh);
+          skeletonMesh.update(0)
+
+          skeletonMesh.rotation.set(-Math.PI / 2, 0, 0);
+          skeletonMesh.position.set(0, 100, 100);
+
+          skeletonMesh.castShadow = true;
+          skeletonMesh.receiveShadow = true;
+
+          skeletonMesh2 = new spine.SkeletonMesh({
+            skeletonData: skeletonData2,
+            premultipliedAlpha: true,
+            materialFactory: param => {
+              param.alphaTest = 0.001;
+              param.premultipliedAlpha = true;
+              return new THREE.MeshStandardMaterial(param);
+            }
+          });
+
+          skeletonMesh2.state.setAnimation(0, animation2, true);
+          scene.add(skeletonMesh2);
+          skeletonMesh2.update(0)
+
+          skeletonMesh2.rotation.set(-Math.PI / 2.4, 0, 0);
+          skeletonMesh2.position.set(0, 150, 100);
+
+          skeletonMesh2.castShadow = true;
+          skeletonMesh2.receiveShadow = true;
+
+
+
+          skeletonMesh3 = new spine.SkeletonMesh({
+            skeletonData: skeletonData3,
+            premultipliedAlpha: true,
+            twoColorTint: true,
+            materialFactory: param => {
+              param.alphaTest = 0.001;
+              param.premultipliedAlpha = true;
+              return new THREE.MeshStandardMaterial(param);
+            }
+          });
+
+          skeletonMesh3.state.setAnimation(0, animation3, true);
+          scene.add(skeletonMesh3);
+          skeletonMesh3.update(0)
+
+          skeletonMesh3.rotation.set(-Math.PI / 2.4, 0, 0);
+          skeletonMesh3.position.set(100, 150, 50);
+
+          skeletonMesh3.castShadow = true;
+          skeletonMesh3.receiveShadow = true;
+
+          skeletonMesh3.update(1.5);
+
+          requestAnimationFrame(render);
+        } else requestAnimationFrame(load);
+      }
+
+      let lastTime = Date.now();
+      function render() {
+        // calculate delta time for animation purposes
+        let now = Date.now() / 1000;
+        let delta = now - lastFrameTime;
+        lastFrameTime = now;
+
+        // resize canvas to use full page, adjust camera/renderer
+        resize();
+
+        // Update orbital controls
+        controls.update();
+
+        // update the animation
+        skeletonMesh.update(delta);
+        skeletonMesh2.update(delta);
+        skeletonMesh3.update(delta);
+
+        // render the scene
+        renderer.render(scene, camera);
+
+        requestAnimationFrame(render);
+      }
+
+      function resize() {
+        let w = window.innerWidth;
+        let h = window.innerHeight;
+        if (canvas.width != w || canvas.height != h) {
+          canvas.width = w;
+          canvas.height = h;
+        }
+
+        camera.aspect = w / h;
+        camera.updateProjectionMatrix();
+
+        renderer.setPixelRatio(window.devicePixelRatio);
+        renderer.setSize(w, h);
+      }
+
+      init();
+    </script>
+  </body>
+</html>

+ 6 - 0
spine-ts/spine-threejs/example/typescript/README.md

@@ -0,0 +1,6 @@
+# spine-threejs TypeScript
+Minimal example project using Pixi, spine-pixi, and TypeScript via NPM and [esbuild](https://esbuild.github.io/).
+
+1. Install dependencies: `npm install`
+2. Build bundle: `npm run build`
+3. Development (run server and recompile in watch mode): `npm run dev`

Plik diff jest za duży
+ 716 - 0
spine-ts/spine-threejs/example/typescript/assets/raptor-pro.json


+ 93 - 0
spine-ts/spine-threejs/example/typescript/assets/raptor.atlas

@@ -0,0 +1,93 @@
+raptor.png
+	size: 1024, 512
+	filter: Linear, Linear
+	scale: 0.5
+back-arm
+	bounds: 895, 295, 46, 25
+back-bracer
+	bounds: 992, 216, 39, 28
+	rotate: 90
+back-hand
+	bounds: 594, 58, 36, 34
+back-knee
+	bounds: 729, 86, 49, 67
+	rotate: 90
+back-thigh
+	bounds: 379, 2, 39, 24
+eyes-open
+	bounds: 902, 194, 47, 45
+	rotate: 90
+front-arm
+	bounds: 945, 306, 48, 26
+front-bracer
+	bounds: 949, 197, 41, 29
+front-hand
+	bounds: 949, 266, 41, 38
+front-open-hand
+	bounds: 875, 148, 43, 44
+front-thigh
+	bounds: 793, 171, 57, 29
+	rotate: 90
+gun
+	bounds: 379, 28, 107, 103
+	rotate: 90
+gun-nohand
+	bounds: 487, 87, 105, 102
+head
+	bounds: 807, 361, 136, 149
+lower-leg
+	bounds: 827, 195, 73, 98
+mouth-grind
+	bounds: 920, 145, 47, 30
+	rotate: 90
+mouth-smile
+	bounds: 992, 257, 47, 30
+	rotate: 90
+neck
+	bounds: 359, 114, 18, 21
+raptor-back-arm
+	bounds: 653, 142, 82, 86
+raptor-body
+	bounds: 2, 277, 632, 233
+raptor-front-arm
+	bounds: 484, 4, 81, 102
+	rotate: 90
+raptor-front-leg
+	bounds: 2, 18, 191, 257
+raptor-hindleg-back
+	bounds: 636, 295, 169, 215
+raptor-horn
+	bounds: 195, 22, 182, 80
+raptor-horn-back
+	bounds: 945, 334, 176, 77
+	rotate: 90
+raptor-jaw
+	bounds: 359, 137, 126, 138
+raptor-jaw-tooth
+	bounds: 895, 322, 37, 48
+	rotate: 90
+raptor-mouth-inside
+	bounds: 949, 228, 36, 41
+	rotate: 90
+raptor-saddle-strap-back
+	bounds: 653, 86, 54, 74
+	rotate: 90
+raptor-saddle-strap-front
+	bounds: 594, 94, 57, 95
+raptor-saddle-w-shadow
+	bounds: 195, 104, 162, 171
+raptor-tail-shadow
+	bounds: 636, 230, 189, 63
+raptor-tongue
+	bounds: 807, 295, 86, 64
+stirrup-back
+	bounds: 952, 151, 44, 35
+	rotate: 90
+stirrup-front
+	bounds: 902, 243, 45, 50
+stirrup-strap
+	bounds: 824, 147, 49, 46
+torso
+	bounds: 737, 137, 54, 91
+visor
+	bounds: 487, 191, 131, 84

BIN
spine-ts/spine-threejs/example/typescript/assets/raptor.png


+ 12 - 0
spine-ts/spine-threejs/example/typescript/index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset='utf-8'>
+    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
+    <title>Pixi Typescript Example</title>
+    <meta name='viewport' content='width=device-width, initial-scale=1'>    
+</head>
+<body>
+    <script src='build/index.js'></script>
+</body>
+</html>

+ 135 - 0
spine-ts/spine-threejs/example/typescript/index.ts

@@ -0,0 +1,135 @@
+import * as THREE from "three";
+import * as spine from "@esotericsoftware/spine-threejs";
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+let scene: THREE.Scene;
+let camera: THREE.PerspectiveCamera;
+let renderer: THREE.WebGLRenderer;
+let geometry, material, mesh, skeletonMesh: spine.SkeletonMesh;
+let atlas;
+let atlasLoader;
+let assetManager: spine.AssetManager;
+let canvas: HTMLCanvasElement;
+let controls: OrbitControls;
+let lastFrameTime = Date.now() / 1000;
+
+let baseUrl = "assets/";
+let skeletonFile = "raptor-pro.json";
+let atlasFile = skeletonFile
+    .replace("-pro", "")
+    .replace("-ess", "")
+    .replace(".json", ".atlas");
+let animation = "walk";
+
+function init() {
+    // create the THREE.JS camera, scene and renderer (WebGL)
+    let width = window.innerWidth,
+    height = window.innerHeight;
+    camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
+    camera.position.y = 100;
+    camera.position.z = 400;
+    scene = new THREE.Scene();
+    renderer = new THREE.WebGLRenderer();
+    renderer.setSize(width, height);
+    document.body.appendChild(renderer.domElement);
+    canvas = renderer.domElement;
+    controls = new OrbitControls(camera, renderer.domElement);
+
+    // LIGHTS - Ambient
+    const ambientLight = new THREE.AmbientLight(0xffffff, 7.0)
+    scene.add(ambientLight)
+
+    // LIGHTS - spotLight
+    const spotLight = new THREE.SpotLight(0xffffff, 5, 1200, Math.PI / 4, 0, 0)
+    spotLight.position.set(0, 1000, 0)
+    spotLight.castShadow = true
+    spotLight.shadow.mapSize.set(8192, 8192)
+    spotLight.shadow.bias = -0.00001;
+    scene.add(spotLight)
+
+    // load the assets required to display the Raptor model
+    assetManager = new spine.AssetManager(baseUrl);
+    assetManager.loadText(skeletonFile);
+    assetManager.loadTextureAtlas(atlasFile);
+
+    requestAnimationFrame(load);
+}
+
+function load() {
+    if (assetManager.isLoadingComplete()) {
+    // Add a box to the scene to which we attach the skeleton mesh
+    geometry = new THREE.BoxGeometry(200, 200, 200);
+    material = new THREE.MeshBasicMaterial({
+        color: 0xff0000,
+        wireframe: true,
+    });
+    mesh = new THREE.Mesh(geometry, material);
+    scene.add(mesh);
+
+    // Load the texture atlas using name.atlas and name.png from the AssetManager.
+    // The function passed to TextureAtlas is used to resolve relative paths.
+    atlas = assetManager.require(atlasFile);
+
+    // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+    atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+
+    // Create a SkeletonJson instance for parsing the .json file.
+    let skeletonJson = new spine.SkeletonJson(atlasLoader);
+
+    // Set the scale to apply during parsing, parse the file, and create a new skeleton.
+    skeletonJson.scale = 0.4;
+    let skeletonData = skeletonJson.readSkeletonData(
+        assetManager.require(skeletonFile)
+    );
+
+    // Create a SkeletonMesh from the data and attach it to the scene
+    skeletonMesh = new spine.SkeletonMesh({
+        skeletonData,
+        materialFactory(parameters) {
+            return new THREE.MeshStandardMaterial({ ...parameters, metalness: .5 });
+        },
+    });
+    skeletonMesh.state.setAnimation(0, animation, true);
+    mesh.add(skeletonMesh);
+
+    requestAnimationFrame(render);
+    } else requestAnimationFrame(load);
+}
+
+let lastTime = Date.now();
+function render() {
+    // calculate delta time for animation purposes
+    let now = Date.now() / 1000;
+    let delta = now - lastFrameTime;
+    lastFrameTime = now;
+
+    // resize canvas to use full page, adjust camera/renderer
+    resize();
+
+    // Update orbital controls
+    controls.update();
+
+    // update the animation
+    skeletonMesh.update(delta);
+
+    // render the scene
+    renderer.render(scene, camera);
+
+    requestAnimationFrame(render);
+}
+
+function resize() {
+    let w = window.innerWidth;
+    let h = window.innerHeight;
+    if (canvas.width != w || canvas.height != h) {
+    canvas.width = w;
+    canvas.height = h;
+    }
+
+    camera.aspect = w / h;
+    camera.updateProjectionMatrix();
+
+    renderer.setSize(w, h);
+}
+
+init();

+ 3168 - 0
spine-ts/spine-threejs/example/typescript/package-lock.json

@@ -0,0 +1,3168 @@
+{
+    "name": "spine-threejs-ts-example",
+    "version": "1.0.0",
+    "lockfileVersion": 3,
+    "requires": true,
+    "packages": {
+        "": {
+            "name": "spine-threejs-ts-example",
+            "version": "1.0.0",
+            "license": "LicenseRef-LICENSE",
+            "dependencies": {
+                "@esotericsoftware/spine-threejs": "4.2.66",
+                "three": "0.170.0"
+            },
+            "devDependencies": {
+                "concurrently": "^7.6.0",
+                "esbuild": "0.17.17",
+                "live-server": "^1.2.2"
+            }
+        },
+        "node_modules/@babel/runtime": {
+            "version": "7.26.0",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+            "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "regenerator-runtime": "^0.14.0"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            }
+        },
+        "node_modules/@esbuild/android-arm": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.17.tgz",
+            "integrity": "sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/android-arm64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz",
+            "integrity": "sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/android-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.17.tgz",
+            "integrity": "sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/darwin-arm64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz",
+            "integrity": "sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/darwin-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz",
+            "integrity": "sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/freebsd-arm64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz",
+            "integrity": "sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/freebsd-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz",
+            "integrity": "sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-arm": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz",
+            "integrity": "sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-arm64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz",
+            "integrity": "sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-ia32": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz",
+            "integrity": "sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-loong64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz",
+            "integrity": "sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==",
+            "cpu": [
+                "loong64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-mips64el": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz",
+            "integrity": "sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==",
+            "cpu": [
+                "mips64el"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-ppc64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz",
+            "integrity": "sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==",
+            "cpu": [
+                "ppc64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-riscv64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz",
+            "integrity": "sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==",
+            "cpu": [
+                "riscv64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-s390x": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz",
+            "integrity": "sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==",
+            "cpu": [
+                "s390x"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/linux-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz",
+            "integrity": "sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/netbsd-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz",
+            "integrity": "sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "netbsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/openbsd-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz",
+            "integrity": "sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "openbsd"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/sunos-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz",
+            "integrity": "sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "sunos"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/win32-arm64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz",
+            "integrity": "sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/win32-ia32": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz",
+            "integrity": "sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esbuild/win32-x64": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz",
+            "integrity": "sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/@esotericsoftware/spine-core": {
+            "version": "4.2.66",
+            "resolved": "https://registry.npmjs.org/@esotericsoftware/spine-core/-/spine-core-4.2.66.tgz",
+            "integrity": "sha512-B1HLyxn0K0K4PcL+5zYkl2iNVI3qwi0PJvEdTJ9vFHrykNBbQ8m3babUDW5ckD4lLD/qF9XeY/h3FoWGZ1KQLw==",
+            "license": "LicenseRef-LICENSE"
+        },
+        "node_modules/@esotericsoftware/spine-threejs": {
+            "version": "4.2.66",
+            "resolved": "https://registry.npmjs.org/@esotericsoftware/spine-threejs/-/spine-threejs-4.2.66.tgz",
+            "integrity": "sha512-3SxGTQMXamchF0txGSAkJMb2aQ/owmqJZp/l/OsKEHGNNTfYgOQq7rPdhwfNCpOkWpVXg6NunIY1iqUBG6z5Ig==",
+            "license": "LicenseRef-LICENSE",
+            "dependencies": {
+                "@esotericsoftware/spine-core": "4.2.66"
+            }
+        },
+        "node_modules/accepts": {
+            "version": "1.3.8",
+            "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+            "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "mime-types": "~2.1.34",
+                "negotiator": "0.6.3"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/ansi-regex": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/ansi-styles": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "color-convert": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=8"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+            }
+        },
+        "node_modules/anymatch": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+            "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+            "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "micromatch": "^3.1.4",
+                "normalize-path": "^2.1.1"
+            }
+        },
+        "node_modules/anymatch/node_modules/normalize-path": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+            "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "remove-trailing-separator": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/apache-crypt": {
+            "version": "1.2.6",
+            "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.6.tgz",
+            "integrity": "sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "unix-crypt-td-js": "^1.1.4"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/apache-md5": {
+            "version": "1.1.8",
+            "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.8.tgz",
+            "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/arr-diff": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+            "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/arr-flatten": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+            "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/arr-union": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+            "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/array-unique": {
+            "version": "0.3.2",
+            "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+            "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/assign-symbols": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+            "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/async-each": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz",
+            "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://paulmillr.com/funding/"
+                }
+            ],
+            "license": "MIT"
+        },
+        "node_modules/atob": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+            "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+            "dev": true,
+            "license": "(MIT OR Apache-2.0)",
+            "bin": {
+                "atob": "bin/atob.js"
+            },
+            "engines": {
+                "node": ">= 4.5.0"
+            }
+        },
+        "node_modules/base": {
+            "version": "0.11.2",
+            "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+            "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "cache-base": "^1.0.1",
+                "class-utils": "^0.3.5",
+                "component-emitter": "^1.2.1",
+                "define-property": "^1.0.0",
+                "isobject": "^3.0.1",
+                "mixin-deep": "^1.2.0",
+                "pascalcase": "^0.1.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/base/node_modules/define-property": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+            "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/basic-auth": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+            "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "safe-buffer": "5.1.2"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/batch": {
+            "version": "0.6.1",
+            "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+            "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/bcryptjs": {
+            "version": "2.4.3",
+            "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+            "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/binary-extensions": {
+            "version": "1.13.1",
+            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+            "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/bindings": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+            "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "file-uri-to-path": "1.0.0"
+            }
+        },
+        "node_modules/braces": {
+            "version": "2.3.2",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+            "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "arr-flatten": "^1.1.0",
+                "array-unique": "^0.3.2",
+                "extend-shallow": "^2.0.1",
+                "fill-range": "^4.0.0",
+                "isobject": "^3.0.1",
+                "repeat-element": "^1.1.2",
+                "snapdragon": "^0.8.1",
+                "snapdragon-node": "^2.0.1",
+                "split-string": "^3.0.2",
+                "to-regex": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/cache-base": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+            "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "collection-visit": "^1.0.0",
+                "component-emitter": "^1.2.1",
+                "get-value": "^2.0.6",
+                "has-value": "^1.0.0",
+                "isobject": "^3.0.1",
+                "set-value": "^2.0.0",
+                "to-object-path": "^0.3.0",
+                "union-value": "^1.0.0",
+                "unset-value": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/chalk": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-styles": "^4.1.0",
+                "supports-color": "^7.1.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/chalk?sponsor=1"
+            }
+        },
+        "node_modules/chalk/node_modules/supports-color": {
+            "version": "7.2.0",
+            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "has-flag": "^4.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/chokidar": {
+            "version": "2.1.8",
+            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+            "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "anymatch": "^2.0.0",
+                "async-each": "^1.0.1",
+                "braces": "^2.3.2",
+                "glob-parent": "^3.1.0",
+                "inherits": "^2.0.3",
+                "is-binary-path": "^1.0.0",
+                "is-glob": "^4.0.0",
+                "normalize-path": "^3.0.0",
+                "path-is-absolute": "^1.0.0",
+                "readdirp": "^2.2.1",
+                "upath": "^1.1.1"
+            },
+            "optionalDependencies": {
+                "fsevents": "^1.2.7"
+            }
+        },
+        "node_modules/class-utils": {
+            "version": "0.3.6",
+            "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+            "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "arr-union": "^3.1.0",
+                "define-property": "^0.2.5",
+                "isobject": "^3.0.0",
+                "static-extend": "^0.1.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/class-utils/node_modules/define-property": {
+            "version": "0.2.5",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+            "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/class-utils/node_modules/is-descriptor": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz",
+            "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/cliui": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+            "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+            "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "string-width": "^4.2.0",
+                "strip-ansi": "^6.0.1",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/collection-visit": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+            "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "map-visit": "^1.0.0",
+                "object-visit": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/color-convert": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "color-name": "~1.1.4"
+            },
+            "engines": {
+                "node": ">=7.0.0"
+            }
+        },
+        "node_modules/color-name": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/colors": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+            "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.1.90"
+            }
+        },
+        "node_modules/component-emitter": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
+            "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
+            "dev": true,
+            "license": "MIT",
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/concurrently": {
+            "version": "7.6.0",
+            "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz",
+            "integrity": "sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "chalk": "^4.1.0",
+                "date-fns": "^2.29.1",
+                "lodash": "^4.17.21",
+                "rxjs": "^7.0.0",
+                "shell-quote": "^1.7.3",
+                "spawn-command": "^0.0.2-1",
+                "supports-color": "^8.1.0",
+                "tree-kill": "^1.2.2",
+                "yargs": "^17.3.1"
+            },
+            "bin": {
+                "conc": "dist/bin/concurrently.js",
+                "concurrently": "dist/bin/concurrently.js"
+            },
+            "engines": {
+                "node": "^12.20.0 || ^14.13.0 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
+            }
+        },
+        "node_modules/connect": {
+            "version": "3.7.0",
+            "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+            "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "debug": "2.6.9",
+                "finalhandler": "1.1.2",
+                "parseurl": "~1.3.3",
+                "utils-merge": "1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.10.0"
+            }
+        },
+        "node_modules/copy-descriptor": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+            "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/core-util-is": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/cors": {
+            "version": "2.8.5",
+            "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+            "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "object-assign": "^4",
+                "vary": "^1"
+            },
+            "engines": {
+                "node": ">= 0.10"
+            }
+        },
+        "node_modules/date-fns": {
+            "version": "2.30.0",
+            "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
+            "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/runtime": "^7.21.0"
+            },
+            "engines": {
+                "node": ">=0.11"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/date-fns"
+            }
+        },
+        "node_modules/debug": {
+            "version": "2.6.9",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ms": "2.0.0"
+            }
+        },
+        "node_modules/decode-uri-component": {
+            "version": "0.2.2",
+            "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+            "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10"
+            }
+        },
+        "node_modules/define-property": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+            "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^1.0.2",
+                "isobject": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/depd": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+            "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/destroy": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+            "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8",
+                "npm": "1.2.8000 || >= 1.4.16"
+            }
+        },
+        "node_modules/duplexer": {
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+            "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/ee-first": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+            "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/emoji-regex": {
+            "version": "8.0.0",
+            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/encodeurl": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/esbuild": {
+            "version": "0.17.17",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.17.tgz",
+            "integrity": "sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==",
+            "dev": true,
+            "hasInstallScript": true,
+            "license": "MIT",
+            "bin": {
+                "esbuild": "bin/esbuild"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "optionalDependencies": {
+                "@esbuild/android-arm": "0.17.17",
+                "@esbuild/android-arm64": "0.17.17",
+                "@esbuild/android-x64": "0.17.17",
+                "@esbuild/darwin-arm64": "0.17.17",
+                "@esbuild/darwin-x64": "0.17.17",
+                "@esbuild/freebsd-arm64": "0.17.17",
+                "@esbuild/freebsd-x64": "0.17.17",
+                "@esbuild/linux-arm": "0.17.17",
+                "@esbuild/linux-arm64": "0.17.17",
+                "@esbuild/linux-ia32": "0.17.17",
+                "@esbuild/linux-loong64": "0.17.17",
+                "@esbuild/linux-mips64el": "0.17.17",
+                "@esbuild/linux-ppc64": "0.17.17",
+                "@esbuild/linux-riscv64": "0.17.17",
+                "@esbuild/linux-s390x": "0.17.17",
+                "@esbuild/linux-x64": "0.17.17",
+                "@esbuild/netbsd-x64": "0.17.17",
+                "@esbuild/openbsd-x64": "0.17.17",
+                "@esbuild/sunos-x64": "0.17.17",
+                "@esbuild/win32-arm64": "0.17.17",
+                "@esbuild/win32-ia32": "0.17.17",
+                "@esbuild/win32-x64": "0.17.17"
+            }
+        },
+        "node_modules/escalade": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+            "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "node_modules/escape-html": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+            "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/etag": {
+            "version": "1.8.1",
+            "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+            "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/event-stream": {
+            "version": "3.3.4",
+            "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+            "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "duplexer": "~0.1.1",
+                "from": "~0",
+                "map-stream": "~0.1.0",
+                "pause-stream": "0.0.11",
+                "split": "0.3",
+                "stream-combiner": "~0.0.4",
+                "through": "~2.3.1"
+            }
+        },
+        "node_modules/expand-brackets": {
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+            "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "debug": "^2.3.3",
+                "define-property": "^0.2.5",
+                "extend-shallow": "^2.0.1",
+                "posix-character-classes": "^0.1.0",
+                "regex-not": "^1.0.0",
+                "snapdragon": "^0.8.1",
+                "to-regex": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/expand-brackets/node_modules/define-property": {
+            "version": "0.2.5",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+            "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/expand-brackets/node_modules/is-descriptor": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz",
+            "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/extend-shallow": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+            "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-extendable": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/extglob": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+            "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "array-unique": "^0.3.2",
+                "define-property": "^1.0.0",
+                "expand-brackets": "^2.1.4",
+                "extend-shallow": "^2.0.1",
+                "fragment-cache": "^0.2.1",
+                "regex-not": "^1.0.0",
+                "snapdragon": "^0.8.1",
+                "to-regex": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/extglob/node_modules/define-property": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+            "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/faye-websocket": {
+            "version": "0.11.4",
+            "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+            "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "dependencies": {
+                "websocket-driver": ">=0.5.1"
+            },
+            "engines": {
+                "node": ">=0.8.0"
+            }
+        },
+        "node_modules/file-uri-to-path": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+            "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true
+        },
+        "node_modules/fill-range": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+            "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "extend-shallow": "^2.0.1",
+                "is-number": "^3.0.0",
+                "repeat-string": "^1.6.1",
+                "to-regex-range": "^2.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/finalhandler": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+            "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "debug": "2.6.9",
+                "encodeurl": "~1.0.2",
+                "escape-html": "~1.0.3",
+                "on-finished": "~2.3.0",
+                "parseurl": "~1.3.3",
+                "statuses": "~1.5.0",
+                "unpipe": "~1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/for-in": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+            "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/fragment-cache": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+            "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "map-cache": "^0.2.2"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/fresh": {
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+            "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/from": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+            "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/fsevents": {
+            "version": "1.2.13",
+            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+            "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+            "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues",
+            "dev": true,
+            "hasInstallScript": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "dependencies": {
+                "bindings": "^1.5.0",
+                "nan": "^2.12.1"
+            },
+            "engines": {
+                "node": ">= 4.0"
+            }
+        },
+        "node_modules/function-bind": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+            "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+            "dev": true,
+            "license": "MIT",
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/get-caller-file": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": "6.* || 8.* || >= 10.*"
+            }
+        },
+        "node_modules/get-value": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+            "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/glob-parent": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+            "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+            "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "is-glob": "^3.1.0",
+                "path-dirname": "^1.0.0"
+            }
+        },
+        "node_modules/glob-parent/node_modules/is-glob": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+            "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-extglob": "^2.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/graceful-fs": {
+            "version": "4.2.11",
+            "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+            "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/has-flag": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/has-value": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+            "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "get-value": "^2.0.6",
+                "has-values": "^1.0.0",
+                "isobject": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/has-values": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+            "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-number": "^3.0.0",
+                "kind-of": "^4.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/has-values/node_modules/kind-of": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+            "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-buffer": "^1.1.5"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/hasown": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+            "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "function-bind": "^1.1.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/http-auth": {
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.1.3.tgz",
+            "integrity": "sha512-Jbx0+ejo2IOx+cRUYAGS1z6RGc6JfYUNkysZM4u4Sfk1uLlGv814F7/PIjQQAuThLdAWxb74JMGd5J8zex1VQg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "apache-crypt": "^1.1.2",
+                "apache-md5": "^1.0.6",
+                "bcryptjs": "^2.3.0",
+                "uuid": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=4.6.1"
+            }
+        },
+        "node_modules/http-errors": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+            "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "depd": "2.0.0",
+                "inherits": "2.0.4",
+                "setprototypeof": "1.2.0",
+                "statuses": "2.0.1",
+                "toidentifier": "1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/http-errors/node_modules/statuses": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/http-parser-js": {
+            "version": "0.5.8",
+            "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+            "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/inherits": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/is-accessor-descriptor": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz",
+            "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "hasown": "^2.0.0"
+            },
+            "engines": {
+                "node": ">= 0.10"
+            }
+        },
+        "node_modules/is-binary-path": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+            "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "binary-extensions": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-buffer": {
+            "version": "1.1.6",
+            "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+            "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/is-data-descriptor": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz",
+            "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "hasown": "^2.0.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/is-descriptor": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz",
+            "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/is-extendable": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+            "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-extglob": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+            "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-fullwidth-code-point": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+            "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/is-glob": {
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+            "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-extglob": "^2.1.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-number": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+            "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "kind-of": "^3.0.2"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-plain-object": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+            "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "isobject": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-windows": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+            "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/is-wsl": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+            "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/isarray": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/isobject": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+            "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/kind-of": {
+            "version": "3.2.2",
+            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+            "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-buffer": "^1.1.5"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/live-server": {
+            "version": "1.2.2",
+            "resolved": "https://registry.npmjs.org/live-server/-/live-server-1.2.2.tgz",
+            "integrity": "sha512-t28HXLjITRGoMSrCOv4eZ88viHaBVIjKjdI5PO92Vxlu+twbk6aE0t7dVIaz6ZWkjPilYFV6OSdMYl9ybN2B4w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "chokidar": "^2.0.4",
+                "colors": "1.4.0",
+                "connect": "^3.6.6",
+                "cors": "latest",
+                "event-stream": "3.3.4",
+                "faye-websocket": "0.11.x",
+                "http-auth": "3.1.x",
+                "morgan": "^1.9.1",
+                "object-assign": "latest",
+                "opn": "latest",
+                "proxy-middleware": "latest",
+                "send": "latest",
+                "serve-index": "^1.9.1"
+            },
+            "bin": {
+                "live-server": "live-server.js"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/lodash": {
+            "version": "4.17.21",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+            "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/map-cache": {
+            "version": "0.2.2",
+            "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+            "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/map-stream": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+            "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+            "dev": true
+        },
+        "node_modules/map-visit": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+            "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "object-visit": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/micromatch": {
+            "version": "3.1.10",
+            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+            "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "arr-diff": "^4.0.0",
+                "array-unique": "^0.3.2",
+                "braces": "^2.3.1",
+                "define-property": "^2.0.2",
+                "extend-shallow": "^3.0.2",
+                "extglob": "^2.0.4",
+                "fragment-cache": "^0.2.1",
+                "kind-of": "^6.0.2",
+                "nanomatch": "^1.2.9",
+                "object.pick": "^1.3.0",
+                "regex-not": "^1.0.0",
+                "snapdragon": "^0.8.1",
+                "to-regex": "^3.0.2"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/micromatch/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/micromatch/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/micromatch/node_modules/kind-of": {
+            "version": "6.0.3",
+            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+            "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/mime-db": {
+            "version": "1.52.0",
+            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/mime-types": {
+            "version": "2.1.35",
+            "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+            "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "mime-db": "1.52.0"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/mixin-deep": {
+            "version": "1.3.2",
+            "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+            "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "for-in": "^1.0.2",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/mixin-deep/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/morgan": {
+            "version": "1.10.0",
+            "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+            "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "basic-auth": "~2.0.1",
+                "debug": "2.6.9",
+                "depd": "~2.0.0",
+                "on-finished": "~2.3.0",
+                "on-headers": "~1.0.2"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/ms": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/nan": {
+            "version": "2.22.0",
+            "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
+            "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true
+        },
+        "node_modules/nanomatch": {
+            "version": "1.2.13",
+            "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+            "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "arr-diff": "^4.0.0",
+                "array-unique": "^0.3.2",
+                "define-property": "^2.0.2",
+                "extend-shallow": "^3.0.2",
+                "fragment-cache": "^0.2.1",
+                "is-windows": "^1.0.2",
+                "kind-of": "^6.0.2",
+                "object.pick": "^1.3.0",
+                "regex-not": "^1.0.0",
+                "snapdragon": "^0.8.1",
+                "to-regex": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/nanomatch/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/nanomatch/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/nanomatch/node_modules/kind-of": {
+            "version": "6.0.3",
+            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+            "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/negotiator": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/normalize-path": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+            "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object-assign": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+            "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object-copy": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+            "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "copy-descriptor": "^0.1.0",
+                "define-property": "^0.2.5",
+                "kind-of": "^3.0.3"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object-copy/node_modules/define-property": {
+            "version": "0.2.5",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+            "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object-copy/node_modules/is-descriptor": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz",
+            "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/object-visit": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+            "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "isobject": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object.pick": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+            "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "isobject": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/on-finished": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+            "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ee-first": "1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/on-headers": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/opn": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz",
+            "integrity": "sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==",
+            "deprecated": "The package has been renamed to `open`",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-wsl": "^1.1.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/parseurl": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/pascalcase": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+            "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/path-dirname": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+            "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/path-is-absolute": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/pause-stream": {
+            "version": "0.0.11",
+            "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+            "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+            "dev": true,
+            "license": [
+                "MIT",
+                "Apache2"
+            ],
+            "dependencies": {
+                "through": "~2.3"
+            }
+        },
+        "node_modules/posix-character-classes": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+            "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/process-nextick-args": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/proxy-middleware": {
+            "version": "0.15.0",
+            "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz",
+            "integrity": "sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.8.0"
+            }
+        },
+        "node_modules/range-parser": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/readable-stream": {
+            "version": "2.3.8",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+            "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "core-util-is": "~1.0.0",
+                "inherits": "~2.0.3",
+                "isarray": "~1.0.0",
+                "process-nextick-args": "~2.0.0",
+                "safe-buffer": "~5.1.1",
+                "string_decoder": "~1.1.1",
+                "util-deprecate": "~1.0.1"
+            }
+        },
+        "node_modules/readdirp": {
+            "version": "2.2.1",
+            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+            "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "graceful-fs": "^4.1.11",
+                "micromatch": "^3.1.10",
+                "readable-stream": "^2.0.2"
+            },
+            "engines": {
+                "node": ">=0.10"
+            }
+        },
+        "node_modules/regenerator-runtime": {
+            "version": "0.14.1",
+            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+            "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/regex-not": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+            "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "extend-shallow": "^3.0.2",
+                "safe-regex": "^1.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/regex-not/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/regex-not/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/remove-trailing-separator": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+            "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/repeat-element": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+            "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/repeat-string": {
+            "version": "1.6.1",
+            "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+            "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10"
+            }
+        },
+        "node_modules/require-directory": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/resolve-url": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+            "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+            "deprecated": "https://github.com/lydell/resolve-url#deprecated",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/ret": {
+            "version": "0.1.15",
+            "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+            "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.12"
+            }
+        },
+        "node_modules/rxjs": {
+            "version": "7.8.1",
+            "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+            "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "dependencies": {
+                "tslib": "^2.1.0"
+            }
+        },
+        "node_modules/safe-buffer": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/safe-regex": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+            "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ret": "~0.1.10"
+            }
+        },
+        "node_modules/send": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/send/-/send-1.1.0.tgz",
+            "integrity": "sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "debug": "^4.3.5",
+                "destroy": "^1.2.0",
+                "encodeurl": "^2.0.0",
+                "escape-html": "^1.0.3",
+                "etag": "^1.8.1",
+                "fresh": "^0.5.2",
+                "http-errors": "^2.0.0",
+                "mime-types": "^2.1.35",
+                "ms": "^2.1.3",
+                "on-finished": "^2.4.1",
+                "range-parser": "^1.2.1",
+                "statuses": "^2.0.1"
+            },
+            "engines": {
+                "node": ">= 18"
+            }
+        },
+        "node_modules/send/node_modules/debug": {
+            "version": "4.3.7",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+            "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/send/node_modules/encodeurl": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+            "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/send/node_modules/ms": {
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+            "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/send/node_modules/on-finished": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ee-first": "1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/send/node_modules/statuses": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/serve-index": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+            "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "accepts": "~1.3.4",
+                "batch": "0.6.1",
+                "debug": "2.6.9",
+                "escape-html": "~1.0.3",
+                "http-errors": "~1.6.2",
+                "mime-types": "~2.1.17",
+                "parseurl": "~1.3.2"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/serve-index/node_modules/depd": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+            "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/serve-index/node_modules/http-errors": {
+            "version": "1.6.3",
+            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+            "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "depd": "~1.1.2",
+                "inherits": "2.0.3",
+                "setprototypeof": "1.1.0",
+                "statuses": ">= 1.4.0 < 2"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/serve-index/node_modules/inherits": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/serve-index/node_modules/setprototypeof": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+            "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/set-value": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+            "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "extend-shallow": "^2.0.1",
+                "is-extendable": "^0.1.1",
+                "is-plain-object": "^2.0.3",
+                "split-string": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/setprototypeof": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/shell-quote": {
+            "version": "1.8.1",
+            "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+            "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
+            "dev": true,
+            "license": "MIT",
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/snapdragon": {
+            "version": "0.8.2",
+            "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+            "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "base": "^0.11.1",
+                "debug": "^2.2.0",
+                "define-property": "^0.2.5",
+                "extend-shallow": "^2.0.1",
+                "map-cache": "^0.2.2",
+                "source-map": "^0.5.6",
+                "source-map-resolve": "^0.5.0",
+                "use": "^3.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/snapdragon-node": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+            "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "define-property": "^1.0.0",
+                "isobject": "^3.0.0",
+                "snapdragon-util": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/snapdragon-node/node_modules/define-property": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+            "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/snapdragon-util": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+            "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "kind-of": "^3.2.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/snapdragon/node_modules/define-property": {
+            "version": "0.2.5",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+            "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/snapdragon/node_modules/is-descriptor": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz",
+            "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/source-map": {
+            "version": "0.5.7",
+            "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+            "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+            "dev": true,
+            "license": "BSD-3-Clause",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/source-map-resolve": {
+            "version": "0.5.3",
+            "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+            "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+            "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "atob": "^2.1.2",
+                "decode-uri-component": "^0.2.0",
+                "resolve-url": "^0.2.1",
+                "source-map-url": "^0.4.0",
+                "urix": "^0.1.0"
+            }
+        },
+        "node_modules/source-map-url": {
+            "version": "0.4.1",
+            "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+            "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+            "deprecated": "See https://github.com/lydell/source-map-url#deprecated",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/spawn-command": {
+            "version": "0.0.2",
+            "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz",
+            "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
+            "dev": true
+        },
+        "node_modules/split": {
+            "version": "0.3.3",
+            "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+            "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "through": "2"
+            },
+            "engines": {
+                "node": "*"
+            }
+        },
+        "node_modules/split-string": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+            "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "extend-shallow": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/split-string/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/split-string/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/static-extend": {
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+            "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "define-property": "^0.2.5",
+                "object-copy": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/static-extend/node_modules/define-property": {
+            "version": "0.2.5",
+            "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+            "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-descriptor": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/static-extend/node_modules/is-descriptor": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz",
+            "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-accessor-descriptor": "^1.0.1",
+                "is-data-descriptor": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/statuses": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+            "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/stream-combiner": {
+            "version": "0.0.4",
+            "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+            "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "duplexer": "~0.1.1"
+            }
+        },
+        "node_modules/string_decoder": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "safe-buffer": "~5.1.0"
+            }
+        },
+        "node_modules/string-width": {
+            "version": "4.2.3",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "emoji-regex": "^8.0.0",
+                "is-fullwidth-code-point": "^3.0.0",
+                "strip-ansi": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/strip-ansi": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-regex": "^5.0.1"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/supports-color": {
+            "version": "8.1.1",
+            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "has-flag": "^4.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/supports-color?sponsor=1"
+            }
+        },
+        "node_modules/three": {
+            "version": "0.170.0",
+            "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz",
+            "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==",
+            "license": "MIT"
+        },
+        "node_modules/through": {
+            "version": "2.3.8",
+            "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+            "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/to-object-path": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+            "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "kind-of": "^3.0.2"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/to-regex": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+            "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "define-property": "^2.0.2",
+                "extend-shallow": "^3.0.2",
+                "regex-not": "^1.0.2",
+                "safe-regex": "^1.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/to-regex-range": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+            "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-number": "^3.0.0",
+                "repeat-string": "^1.6.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/to-regex/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/to-regex/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/toidentifier": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+            "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.6"
+            }
+        },
+        "node_modules/tree-kill": {
+            "version": "1.2.2",
+            "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+            "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+            "dev": true,
+            "license": "MIT",
+            "bin": {
+                "tree-kill": "cli.js"
+            }
+        },
+        "node_modules/tslib": {
+            "version": "2.8.1",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+            "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+            "dev": true,
+            "license": "0BSD"
+        },
+        "node_modules/union-value": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+            "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "arr-union": "^3.1.0",
+                "get-value": "^2.0.6",
+                "is-extendable": "^0.1.1",
+                "set-value": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/unix-crypt-td-js": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz",
+            "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==",
+            "dev": true,
+            "license": "BSD-3-Clause"
+        },
+        "node_modules/unpipe": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+            "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/unset-value": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+            "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "has-value": "^0.3.1",
+                "isobject": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/unset-value/node_modules/has-value": {
+            "version": "0.3.1",
+            "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+            "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "get-value": "^2.0.3",
+                "has-values": "^0.1.4",
+                "isobject": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+            "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "isarray": "1.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/unset-value/node_modules/has-values": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+            "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/upath": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+            "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4",
+                "yarn": "*"
+            }
+        },
+        "node_modules/urix": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+            "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+            "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/use": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+            "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/util-deprecate": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/utils-merge": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+            "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4.0"
+            }
+        },
+        "node_modules/uuid": {
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+            "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+            "deprecated": "Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.",
+            "dev": true,
+            "license": "MIT",
+            "bin": {
+                "uuid": "bin/uuid"
+            }
+        },
+        "node_modules/vary": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+            "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/websocket-driver": {
+            "version": "0.7.4",
+            "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+            "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "dependencies": {
+                "http-parser-js": ">=0.5.1",
+                "safe-buffer": ">=5.1.0",
+                "websocket-extensions": ">=0.1.1"
+            },
+            "engines": {
+                "node": ">=0.8.0"
+            }
+        },
+        "node_modules/websocket-extensions": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+            "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": ">=0.8.0"
+            }
+        },
+        "node_modules/wrap-ansi": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-styles": "^4.0.0",
+                "string-width": "^4.1.0",
+                "strip-ansi": "^6.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+            }
+        },
+        "node_modules/y18n": {
+            "version": "5.0.8",
+            "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+            "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/yargs": {
+            "version": "17.7.2",
+            "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+            "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "cliui": "^8.0.1",
+                "escalade": "^3.1.1",
+                "get-caller-file": "^2.0.5",
+                "require-directory": "^2.1.1",
+                "string-width": "^4.2.3",
+                "y18n": "^5.0.5",
+                "yargs-parser": "^21.1.1"
+            },
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/yargs-parser": {
+            "version": "21.1.1",
+            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+            "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">=12"
+            }
+        }
+    }
+}

+ 20 - 0
spine-ts/spine-threejs/example/typescript/package.json

@@ -0,0 +1,20 @@
+{
+    "name": "spine-threejs-ts-example",
+    "description": "Spine threejs ts example",
+    "author": "Esoteric Software LLC",
+    "license": "LicenseRef-LICENSE",
+    "version": "1.0.0",
+    "scripts": {
+        "build":"npx esbuild index.ts --bundle --sourcemap --outfile=build/index.js",
+        "dev": "npx concurrently \"npx live-server --no-browser\" \"npm run build -- --watch\""
+    },
+    "dependencies": {
+        "@esotericsoftware/spine-threejs": "4.2.67",
+        "three": "0.162.0"
+    },
+    "devDependencies": {
+        "esbuild": "0.17.17",
+        "concurrently": "^7.6.0",
+        "live-server": "^1.2.2"
+    }
+}

+ 6 - 0
spine-ts/spine-threejs/package.json

@@ -32,5 +32,11 @@
   "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
   "dependencies": {
     "@esotericsoftware/spine-core": "4.2.66"
+  },
+  "devDependencies": {
+    "@types/three": "0.162.0"
+  },
+  "peerDependencies": {
+    "three": "0.162.0"
   }
 }

+ 226 - 34
spine-ts/spine-threejs/src/MeshBatcher.ts

@@ -27,13 +27,18 @@
  * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
-import { SkeletonMeshMaterial, SkeletonMeshMaterialParametersCustomizer } from "./SkeletonMesh.js";
 import * as THREE from "three"
+
 import { ThreeJsTexture, ThreeBlendOptions } from "./ThreeJsTexture.js";
 import { BlendMode } from "@esotericsoftware/spine-core";
+import { SkeletonMesh } from "./SkeletonMesh.js";
 
+export type MaterialWithMap = THREE.Material & { map: THREE.Texture | null };
 export class MeshBatcher extends THREE.Mesh {
-	private static VERTEX_SIZE = 9;
+	public static MAX_VERTICES = 10920;
+
+	// private static VERTEX_SIZE = 9;
+	private vertexSize = 9;
 	private vertexBuffer: THREE.InterleavedBuffer;
 	private vertices: Float32Array;
 	private verticesLength = 0;
@@ -41,23 +46,36 @@ export class MeshBatcher extends THREE.Mesh {
 	private indicesLength = 0;
 	private materialGroups: [number, number, number][] = [];
 
-	constructor (maxVertices: number = 10920, private materialCustomizer: SkeletonMeshMaterialParametersCustomizer = (parameters) => { }) {
+	constructor (
+		maxVertices: number = MeshBatcher.MAX_VERTICES,
+		private materialFactory: (parameters: THREE.MaterialParameters) => MaterialWithMap,
+		private twoColorTint = true,
+	) {
 		super();
-		if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
-		let vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE);
+
+		if (maxVertices > MeshBatcher.MAX_VERTICES) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
+
+		if (twoColorTint) {
+			this.vertexSize += 3;
+		}
+
+		let vertices = this.vertices = new Float32Array(maxVertices * this.vertexSize);
 		let indices = this.indices = new Uint16Array(maxVertices * 3);
 		let geo = new THREE.BufferGeometry();
-		let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE);
+		let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, this.vertexSize);
 		vertexBuffer.usage = WebGLRenderingContext.DYNAMIC_DRAW;
 		geo.setAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false));
 		geo.setAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false));
 		geo.setAttribute("uv", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 7, false));
+		if (twoColorTint) {
+			geo.setAttribute("darkcolor", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 9, false));
+		}
 		geo.setIndex(new THREE.BufferAttribute(indices, 1));
 		geo.getIndex()!.usage = WebGLRenderingContext.DYNAMIC_DRAW;
 		geo.drawRange.start = 0;
 		geo.drawRange.count = 0;
 		this.geometry = geo;
-		this.material = [new SkeletonMeshMaterial(materialCustomizer)];
+		this.material = [];
 	}
 
 	dispose () {
@@ -80,13 +98,13 @@ export class MeshBatcher extends THREE.Mesh {
 		geo.clearGroups();
 		this.materialGroups = [];
 		if (this.material instanceof THREE.Material) {
-			const meshMaterial = this.material as SkeletonMeshMaterial;
-			meshMaterial.uniforms.map.value = null;
+			const meshMaterial = this.material as MaterialWithMap;
+			meshMaterial.map = null;
 			meshMaterial.blending = THREE.NormalBlending;
 		} else if (Array.isArray(this.material)) {
 			for (let i = 0; i < this.material.length; i++) {
-				const meshMaterial = this.material[i] as SkeletonMeshMaterial;
-				meshMaterial.uniforms.map.value = null;
+				const meshMaterial = this.material[i] as MaterialWithMap;
+				meshMaterial.map = null;
 				meshMaterial.blending = THREE.NormalBlending;
 			}
 		}
@@ -100,25 +118,48 @@ export class MeshBatcher extends THREE.Mesh {
 
 	canBatch (numVertices: number, numIndices: number) {
 		if (this.indicesLength + numIndices >= this.indices.byteLength / 2) return false;
-		if (this.verticesLength / MeshBatcher.VERTEX_SIZE + numVertices >= (this.vertices.byteLength / 4) / MeshBatcher.VERTEX_SIZE) return false;
+		if (this.verticesLength / this.vertexSize + numVertices >= (this.vertices.byteLength / 4) / this.vertexSize) return false;
 		return true;
 	}
 
 	batch (vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z: number = 0) {
-		let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE;
+		let indexStart = this.verticesLength / this.vertexSize;
 		let vertexBuffer = this.vertices;
 		let i = this.verticesLength;
 		let j = 0;
-		for (; j < verticesLength;) {
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = z;
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
-			vertexBuffer[i++] = vertices[j++];
+		if (this.twoColorTint) {
+			for (; j < verticesLength;) {
+				vertexBuffer[i++] = vertices[j++];  // x
+				vertexBuffer[i++] = vertices[j++];  // y
+				vertexBuffer[i++] = z;				// z
+
+				vertexBuffer[i++] = vertices[j++];  // r
+				vertexBuffer[i++] = vertices[j++];  // g
+				vertexBuffer[i++] = vertices[j++];  // b
+				vertexBuffer[i++] = vertices[j++];  // a
+
+				vertexBuffer[i++] = vertices[j++];  // u
+				vertexBuffer[i++] = vertices[j++];  // v
+
+				vertexBuffer[i++] = vertices[j++];  // dark r
+				vertexBuffer[i++] = vertices[j++];  // dark g
+				vertexBuffer[i++] = vertices[j++];  // dark b
+				j++;
+			}
+		} else {
+			for (; j < verticesLength;) {
+				vertexBuffer[i++] = vertices[j++];  // x
+				vertexBuffer[i++] = vertices[j++];  // y
+				vertexBuffer[i++] = z;				// z
+
+				vertexBuffer[i++] = vertices[j++];  // r
+				vertexBuffer[i++] = vertices[j++];  // g
+				vertexBuffer[i++] = vertices[j++];  // b
+				vertexBuffer[i++] = vertices[j++];  // a
+
+				vertexBuffer[i++] = vertices[j++];  // u
+				vertexBuffer[i++] = vertices[j++];  // v
+			}
 		}
 		this.verticesLength = i;
 
@@ -130,17 +171,16 @@ export class MeshBatcher extends THREE.Mesh {
 
 	end () {
 		this.vertexBuffer.needsUpdate = this.verticesLength > 0;
-		this.vertexBuffer.updateRange.offset = 0;
-		this.vertexBuffer.updateRange.count = this.verticesLength;
+		this.vertexBuffer.addUpdateRange(0, this.verticesLength);
 		let geo = (<THREE.BufferGeometry>this.geometry);
 		this.closeMaterialGroups();
 		let index = geo.getIndex();
 		if (!index) throw new Error("BufferAttribute must not be null.");
 		index.needsUpdate = this.indicesLength > 0;
-		index.updateRange.offset = 0;
-		index.updateRange.count = this.indicesLength;
+		index.addUpdateRange(0, this.indicesLength);
 		geo.drawRange.start = 0;
 		geo.drawRange.count = this.indicesLength;
+		geo.computeVertexNormals();
 	}
 
 	addMaterialGroup (indicesLength: number, materialGroup: number) {
@@ -168,14 +208,14 @@ export class MeshBatcher extends THREE.Mesh {
 
 		if (Array.isArray(this.material)) {
 			for (let i = 0; i < this.material.length; i++) {
-				const meshMaterial = this.material[i] as SkeletonMeshMaterial;
+				const meshMaterial = this.material[i] as MaterialWithMap;
 
-				if (!meshMaterial.uniforms.map.value) {
+				if (!meshMaterial.map) {
 					updateMeshMaterial(meshMaterial, slotTexture, blendingObject);
 					return i;
 				}
 
-				if (meshMaterial.uniforms.map.value === slotTexture
+				if (meshMaterial.map === slotTexture
 					&& blendingObject.blending === meshMaterial.blending
 					&& (blendingObject.blendSrc === undefined || blendingObject.blendSrc === meshMaterial.blendSrc)
 					&& (blendingObject.blendDst === undefined || blendingObject.blendDst === meshMaterial.blendDst)
@@ -186,8 +226,8 @@ export class MeshBatcher extends THREE.Mesh {
 				}
 			}
 
-			const meshMaterial = new SkeletonMeshMaterial(this.materialCustomizer);
-			updateMeshMaterial(meshMaterial, slotTexture, blendingObject);
+			const meshMaterial = this.newMaterial();
+			updateMeshMaterial(meshMaterial as MaterialWithMap, slotTexture, blendingObject);
 			this.material.push(meshMaterial);
 			group = this.material.length - 1;
 		} else {
@@ -196,10 +236,162 @@ export class MeshBatcher extends THREE.Mesh {
 
 		return group;
 	}
+
+	private newMaterial (): MaterialWithMap {
+		const meshMaterial = this.materialFactory(SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS);
+
+		if (!('map' in meshMaterial)) {
+			throw new Error("The material factory must return a material having the map property for the texture.");
+		}
+
+		if (meshMaterial instanceof SkeletonMeshMaterial) {
+			return meshMaterial;
+		}
+
+		if (this.twoColorTint) {
+			meshMaterial.defines = {
+				...meshMaterial.defines,
+				USE_SPINE_DARK_TINT: 1,
+			}
+		}
+
+		meshMaterial.onBeforeCompile = spineOnBeforeCompile;
+
+		return meshMaterial;
+	}
+}
+
+const spineOnBeforeCompile = (shader: THREE.WebGLProgramParametersWithUniforms) => {
+
+	let code;
+
+	// VERTEX SHADER MODIFICATIONS
+
+	// Add dark color attribute
+	shader.vertexShader = `
+		#if defined( USE_SPINE_DARK_TINT )
+			attribute vec3 darkcolor;
+		#endif
+	` + shader.vertexShader;
+
+	// Add dark color attribute
+	code = `
+		#if defined( USE_SPINE_DARK_TINT )
+			varying vec3 v_dark;
+		#endif
+	`;
+	shader.vertexShader = insertAfterElementInShader(shader.vertexShader, '#include <color_pars_vertex>', code);
+
+	// Define v_dark varying
+	code = `
+		#if defined( USE_SPINE_DARK_TINT )
+			v_dark = vec3( 1.0 );
+			v_dark *= darkcolor;
+		#endif
+	`;
+	shader.vertexShader = insertAfterElementInShader(shader.vertexShader, '#include <color_vertex>', code);
+
+
+	// FRAGMENT SHADER MODIFICATIONS
+
+	// Define v_dark varying
+	code = `
+		#ifdef USE_SPINE_DARK_TINT
+			varying vec3 v_dark;
+		#endif
+	`;
+	shader.fragmentShader = insertAfterElementInShader(shader.fragmentShader, '#include <color_pars_fragment>', code);
+
+	// Replacing color_fragment with the addition of dark tint formula if twoColorTint is true
+	shader.fragmentShader = shader.fragmentShader.replace(
+		'#include <color_fragment>',
+		`
+			#ifdef USE_SPINE_DARK_TINT
+				#ifdef USE_COLOR_ALPHA
+						diffuseColor.a *= vColor.a;
+						diffuseColor.rgb *= (1.0 - diffuseColor.rgb) * v_dark.rgb + diffuseColor.rgb * vColor.rgb;
+				#endif
+			#else
+				#ifdef USE_COLOR_ALPHA
+						diffuseColor *= vColor;
+				#endif
+			#endif
+		`
+	);
+
+	// We had to remove this because we need premultiplied blending modes, but our textures are already premultiplied
+	// We could actually create a custom blending mode for Normal and Additive too
+	shader.fragmentShader = shader.fragmentShader.replace('#include <premultiplied_alpha_fragment>', '');
+
+	// We had to remove this (and don't assign a color space to the texture) otherwise we would see artifacts on texture edges
+	shader.fragmentShader = shader.fragmentShader.replace('#include <colorspace_fragment>', '');
+
 }
 
-function updateMeshMaterial (meshMaterial: SkeletonMeshMaterial, slotTexture: THREE.Texture, blending: ThreeBlendOptions) {
-	meshMaterial.uniforms.map.value = slotTexture;
+function insertAfterElementInShader (shader: string, elementToFind: string, codeToInsert: string) {
+	const index = shader.indexOf(elementToFind);
+	const beforeToken = shader.slice(0, index + elementToFind.length);
+	const afterToken = shader.slice(index + elementToFind.length);
+	return beforeToken + codeToInsert + afterToken;
+}
+
+function updateMeshMaterial (meshMaterial: MaterialWithMap, slotTexture: THREE.Texture, blending: ThreeBlendOptions) {
+	meshMaterial.map = slotTexture;
 	Object.assign(meshMaterial, blending);
 	meshMaterial.needsUpdate = true;
 }
+
+
+export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
+
+	public get map (): THREE.Texture | null {
+		return this.uniforms.map.value;
+	}
+
+	public set map (value: THREE.Texture | null) {
+		this.uniforms.map.value = value;
+	}
+
+	constructor (parameters: THREE.ShaderMaterialParameters) {
+
+		let vertexShader = `
+			varying vec2 vUv;
+			varying vec4 vColor;
+			void main() {
+				vUv = uv;
+				vColor = color;
+				gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
+			}
+		`;
+		let fragmentShader = `
+			uniform sampler2D map;
+			#ifdef USE_SPINE_ALPHATEST
+			uniform float alphaTest;
+			#endif
+			varying vec2 vUv;
+			varying vec4 vColor;
+			void main(void) {
+				gl_FragColor = texture2D(map, vUv)*vColor;
+				#ifdef USE_SPINE_ALPHATEST
+					if (gl_FragColor.a < alphaTest) discard;
+				#endif
+			}
+		`;
+
+		let uniforms = { map: { value: null } };
+		if (parameters.uniforms) {
+			uniforms = { ...parameters.uniforms, ...uniforms };
+		}
+
+		if (parameters.alphaTest && parameters.alphaTest > 0) {
+			parameters.defines = { USE_SPINE_ALPHATEST: 1 };
+		}
+
+		super({
+			vertexShader,
+			fragmentShader,
+			...parameters,
+			uniforms,
+		});
+	}
+}

+ 143 - 78
spine-ts/spine-threejs/src/SkeletonMesh.ts

@@ -27,10 +27,10 @@
  * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
+import * as THREE from "three";
 import {
 	AnimationState,
 	AnimationStateData,
-	BlendMode,
 	ClippingAttachment,
 	Color,
 	MeshAttachment,
@@ -40,69 +40,51 @@ import {
 	Skeleton,
 	SkeletonClipping,
 	SkeletonData,
-	TextureAtlasRegion,
+	SkeletonBinary,
+	SkeletonJson,
 	Utils,
 	Vector2,
 } from "@esotericsoftware/spine-core";
-import { MeshBatcher } from "./MeshBatcher.js";
-import * as THREE from "three";
+
+import { MaterialWithMap, MeshBatcher } from "./MeshBatcher.js";
 import { ThreeJsTexture } from "./ThreeJsTexture.js";
 
-export type SkeletonMeshMaterialParametersCustomizer = (
-	materialParameters: THREE.ShaderMaterialParameters
-) => void;
-
-export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
-	constructor (customizer: SkeletonMeshMaterialParametersCustomizer) {
-		let vertexShader = `
-			attribute vec4 color;
-			varying vec2 vUv;
-			varying vec4 vColor;
-			void main() {
-				vUv = uv;
-				vColor = color;
-				gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
-			}
-		`;
-		let fragmentShader = `
-			uniform sampler2D map;
-			#ifdef USE_SPINE_ALPHATEST
-			uniform float alphaTest;
-			#endif
-			varying vec2 vUv;
-			varying vec4 vColor;
-			void main(void) {
-				gl_FragColor = texture2D(map, vUv)*vColor;
-				#ifdef USE_SPINE_ALPHATEST
-				if (gl_FragColor.a < alphaTest) discard;
-				#endif
-			}
-		`;
+type SkeletonMeshMaterialParametersCustomizer = (materialParameters: THREE.MaterialParameters) => void;
+type SkeletonMeshConfiguration = {
 
-		let parameters: THREE.ShaderMaterialParameters = {
-			uniforms: {
-				map: { value: null },
-			},
-			vertexShader: vertexShader,
-			fragmentShader: fragmentShader,
-			side: THREE.DoubleSide,
-			transparent: true,
-			depthWrite: true,
-			alphaTest: 0.0,
-		};
-		customizer(parameters);
-		if (parameters.alphaTest && parameters.alphaTest > 0) {
-			parameters.defines = { USE_SPINE_ALPHATEST: 1 };
-			if (!parameters.uniforms) parameters.uniforms = {};
-			parameters.uniforms["alphaTest"] = { value: parameters.alphaTest };
-		}
-		super(parameters);
-		// non-pma textures are premultiply on upload, so we set premultipliedAlpha to true
-		this.premultipliedAlpha = true;
-	}
-}
+	/** The skeleton data object loaded by using {@link SkeletonJson} or {@link SkeletonBinary} */
+	skeletonData: SkeletonData,
+
+	/** Set it to true to enable tint black rendering */
+	twoColorTint?: boolean,
+
+	/**
+	 * The function used to create the materials for the meshes composing this Object3D.
+	 * The material used must have the `map` property.
+	 * By default a MeshStandardMaterial is used, so no light and shadows are available.
+	 * Use a MeshStandardMaterial
+	 *
+	 * @param parameters The default parameters with which this function is invoked.
+	 * You should pass this parameters, once personalized, to the costructor of the material you want to use.
+	 * Default values are defined in {@link SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS}.
+	 *
+	 * @returns An instance of the material you want to be used for the meshes of this Object3D. The material must have the `map` property.
+	 */
+	materialFactory?: (parameters: THREE.MaterialParameters) => MaterialWithMap,
+};
 
 export class SkeletonMesh extends THREE.Object3D {
+	// public static readonly DEFAULT_MATERIAL_PARAMETERS: THREE.MaterialParameters = {
+	public static readonly DEFAULT_MATERIAL_PARAMETERS: THREE.MaterialParameters = {
+		side: THREE.DoubleSide,
+		depthWrite: true,
+		depthTest: true,
+		transparent: true,
+		alphaTest: 0.001,
+		vertexColors: true,
+		premultipliedAlpha: true,
+	}
+
 	tempPos: Vector2 = new Vector2();
 	tempUv: Vector2 = new Vector2();
 	tempLight = new Color();
@@ -112,26 +94,87 @@ export class SkeletonMesh extends THREE.Object3D {
 	zOffset: number = 0.1;
 
 	private batches = new Array<MeshBatcher>();
+	private materialFactory: (parameters: THREE.MaterialParameters) => MaterialWithMap;
 	private nextBatchIndex = 0;
 	private clipper: SkeletonClipping = new SkeletonClipping();
 
 	static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
 	static VERTEX_SIZE = 2 + 2 + 4;
+	private vertexSize = 2 + 2 + 4;
+	private twoColorTint;
 
 	private vertices = Utils.newFloatArray(1024);
 	private tempColor = new Color();
+	private tempDarkColor = new Color();
+
+	private _castShadow = false;
+	private _receiveShadow = false;
 
+	/**
+	 * Create an Object3D containing meshes representing your Spine animation.
+	 * Personalize your material providing a {@link SkeletonMeshConfiguration}
+	 * @param skeletonData
+	 */
+	constructor (configuration: SkeletonMeshConfiguration)
+	/**
+	 * @deprecated This signature is deprecated, please use the one with a single {@link SkeletonMeshConfiguration} parameter
+	 */
 	constructor (
 		skeletonData: SkeletonData,
-		private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (
-			material
-		) => { }
+		materialCustomizer: SkeletonMeshMaterialParametersCustomizer,
+	)
+	constructor (
+		skeletonDataOrConfiguration: SkeletonData | SkeletonMeshConfiguration,
+		materialCustomizer: SkeletonMeshMaterialParametersCustomizer = () => { }
 	) {
 		super();
 
-		this.skeleton = new Skeleton(skeletonData);
-		let animData = new AnimationStateData(skeletonData);
+		if (!('skeletonData' in skeletonDataOrConfiguration)) {
+			const materialFactory = () => {
+				const parameters: THREE.MaterialParameters = { ...SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS };
+				materialCustomizer(parameters);
+				return new THREE.MeshBasicMaterial(parameters);
+			};
+			skeletonDataOrConfiguration = {
+				skeletonData: skeletonDataOrConfiguration,
+				materialFactory,
+			}
+		}
+
+		this.twoColorTint = skeletonDataOrConfiguration.twoColorTint ?? true;
+		if (this.twoColorTint) {
+			this.vertexSize += 4;
+		}
+
+		this.materialFactory = skeletonDataOrConfiguration.materialFactory ?? (() => new THREE.MeshBasicMaterial(SkeletonMesh.DEFAULT_MATERIAL_PARAMETERS));
+		this.skeleton = new Skeleton(skeletonDataOrConfiguration.skeletonData);
+		let animData = new AnimationStateData(skeletonDataOrConfiguration.skeletonData);
 		this.state = new AnimationState(animData);
+
+		Object.defineProperty(this, 'castShadow', {
+			get: () => this._castShadow,
+			set: (value: boolean) => {
+				this._castShadow = value;
+				this.traverse((child) => {
+					if (child instanceof MeshBatcher) {
+						child.castShadow = value;
+					}
+				});
+			},
+		});
+
+		Object.defineProperty(this, 'receiveShadow', {
+			get: () => this._receiveShadow,
+			set: (value: boolean) => {
+				this._receiveShadow = value;
+				// Propagate to children
+				this.traverse((child) => {
+					if (child instanceof MeshBatcher) {
+						child.receiveShadow = value;
+					}
+				});
+			},
+		});
 	}
 
 	update (deltaTime: number) {
@@ -162,7 +205,9 @@ export class SkeletonMesh extends THREE.Object3D {
 
 	private nextBatch () {
 		if (this.batches.length == this.nextBatchIndex) {
-			let batch = new MeshBatcher(10920, this.materialCustomerizer);
+			let batch = new MeshBatcher(MeshBatcher.MAX_VERTICES, this.materialFactory, this.twoColorTint);
+			batch.castShadow = this._castShadow;
+			batch.receiveShadow = this._receiveShadow;
 			this.add(batch);
 			this.batches.push(batch);
 		}
@@ -174,8 +219,6 @@ export class SkeletonMesh extends THREE.Object3D {
 	private updateGeometry () {
 		this.clearBatches();
 
-		let tempPos = this.tempPos;
-		let tempUv = this.tempUv;
 		let tempLight = this.tempLight;
 		let tempDark = this.tempDark;
 		let clipper = this.clipper;
@@ -189,7 +232,7 @@ export class SkeletonMesh extends THREE.Object3D {
 		let z = 0;
 		let zOffset = this.zOffset;
 		for (let i = 0, n = drawOrder.length; i < n; i++) {
-			let vertexSize = clipper.isClipping() ? 2 : SkeletonMesh.VERTEX_SIZE;
+			let vertexSize = clipper.isClipping() ? 2 : this.vertexSize;
 			let slot = drawOrder[i];
 			if (!slot.bone.active) {
 				clipper.clipEndWithSlot(slot);
@@ -249,6 +292,16 @@ export class SkeletonMesh extends THREE.Object3D {
 					alpha
 				);
 
+				let darkColor = this.tempDarkColor;
+				if (!slot.darkColor)
+					darkColor.set(1, 1, 1, 0);
+				else {
+					darkColor.r = slot.darkColor.r * alpha;
+					darkColor.g = slot.darkColor.g * alpha;
+					darkColor.b = slot.darkColor.b * alpha;
+					darkColor.a = 1;
+				}
+
 				let finalVertices: NumberArrayLike;
 				let finalVerticesLength: number;
 				let finalIndices: NumberArrayLike;
@@ -262,7 +315,7 @@ export class SkeletonMesh extends THREE.Object3D {
 						uvs,
 						color,
 						tempLight,
-						false
+						this.twoColorTint,
 					);
 					let clippedVertices = clipper.clippedVertices;
 					let clippedTriangles = clipper.clippedTriangles;
@@ -272,18 +325,30 @@ export class SkeletonMesh extends THREE.Object3D {
 					finalIndicesLength = clippedTriangles.length;
 				} else {
 					let verts = vertices;
-					for (
-						let v = 2, u = 0, n = numFloats;
-						v < n;
-						v += vertexSize, u += 2
-					) {
-						verts[v] = color.r;
-						verts[v + 1] = color.g;
-						verts[v + 2] = color.b;
-						verts[v + 3] = color.a;
-						verts[v + 4] = uvs[u];
-						verts[v + 5] = uvs[u + 1];
+					if (!this.twoColorTint) {
+						for (let v = 2, u = 0, n = numFloats; v < n; v += vertexSize, u += 2) {
+							verts[v] = color.r;
+							verts[v + 1] = color.g;
+							verts[v + 2] = color.b;
+							verts[v + 3] = color.a;
+							verts[v + 4] = uvs[u];
+							verts[v + 5] = uvs[u + 1];
+						}
+					} else {
+						for (let v = 2, u = 0, n = numFloats; v < n; v += vertexSize, u += 2) {
+							verts[v] = color.r;
+							verts[v + 1] = color.g;
+							verts[v + 2] = color.b;
+							verts[v + 3] = color.a;
+							verts[v + 4] = uvs[u];
+							verts[v + 5] = uvs[u + 1];
+							verts[v + 6] = darkColor.r;
+							verts[v + 7] = darkColor.g;
+							verts[v + 8] = darkColor.b;
+							verts[v + 9] = darkColor.a;
+						}
 					}
+
 					finalVertices = vertices;
 					finalVerticesLength = numFloats;
 					finalIndices = triangles;
@@ -298,7 +363,7 @@ export class SkeletonMesh extends THREE.Object3D {
 				// Start new batch if this one can't hold vertices/indices
 				if (
 					!batch.canBatch(
-						finalVerticesLength / SkeletonMesh.VERTEX_SIZE,
+						finalVerticesLength / this.vertexSize,
 						finalIndicesLength
 					)
 				) {

+ 19 - 3
spine-ts/spine-threejs/src/ThreeJsTexture.ts

@@ -42,12 +42,16 @@ export class ThreeJsTexture extends Texture {
 		// if the texture is not pma, we ask to threejs to premultiply on upload
 		this.texture.premultiplyAlpha = !pma;
 		this.texture.flipY = false;
+
+		// Keep this as a reference - this is necessary in future versions of ThreeJS
+		// this.texture.colorSpace = THREE.SRGBColorSpace;
+
 		this.texture.needsUpdate = true;
 	}
 
 	setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
-		this.texture.minFilter = ThreeJsTexture.toThreeJsTextureFilter(minFilter);
-		this.texture.magFilter = ThreeJsTexture.toThreeJsTextureFilter(magFilter);
+		this.texture.minFilter = ThreeJsTexture.toThreeJsMinificationTextureFilter(minFilter);
+		this.texture.magFilter = ThreeJsTexture.toThreeJsMagnificationTextureFilter(magFilter);
 	}
 
 	setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
@@ -59,7 +63,7 @@ export class ThreeJsTexture extends Texture {
 		this.texture.dispose();
 	}
 
-	static toThreeJsTextureFilter (filter: TextureFilter) {
+	static toThreeJsMinificationTextureFilter (filter: TextureFilter): THREE.MinificationTextureFilter {
 		if (filter === TextureFilter.Linear) return THREE.LinearFilter;
 		else if (filter === TextureFilter.MipMap) return THREE.LinearMipMapLinearFilter; // also includes TextureFilter.MipMapLinearLinear
 		else if (filter === TextureFilter.MipMapLinearNearest) return THREE.LinearMipMapNearestFilter;
@@ -69,6 +73,16 @@ export class ThreeJsTexture extends Texture {
 		else throw new Error("Unknown texture filter: " + filter);
 	}
 
+	static toThreeJsMagnificationTextureFilter (filter: TextureFilter): THREE.MagnificationTextureFilter {
+		if (filter === TextureFilter.Linear) return THREE.LinearFilter;
+		else if (filter === TextureFilter.MipMap) return THREE.LinearFilter;
+		else if (filter === TextureFilter.MipMapLinearNearest) return THREE.NearestFilter;
+		else if (filter === TextureFilter.MipMapNearestLinear) return THREE.LinearFilter;
+		else if (filter === TextureFilter.MipMapNearestNearest) return THREE.NearestFilter;
+		else if (filter === TextureFilter.Nearest) return THREE.NearestFilter;
+		else throw new Error("Unknown texture filter: " + filter);
+	}
+
 	static toThreeJsTextureWrap (wrap: TextureWrap) {
 		if (wrap === TextureWrap.ClampToEdge) return THREE.ClampToEdgeWrapping;
 		else if (wrap === TextureWrap.MirroredRepeat) return THREE.MirroredRepeatWrapping;
@@ -76,9 +90,11 @@ export class ThreeJsTexture extends Texture {
 		else throw new Error("Unknown texture wrap: " + wrap);
 	}
 
+	static fist = true;
 	static toThreeJsBlending (blend: BlendMode): ThreeBlendOptions {
 		if (blend === BlendMode.Normal) return { blending: THREE.NormalBlending };
 		else if (blend === BlendMode.Additive) return { blending: THREE.AdditiveBlending };
+		// else if (blend === BlendMode.Multiply) return { blending: THREE.NormalBlending };
 		else if (blend === BlendMode.Multiply) return {
 			blending: THREE.CustomBlending,
 			blendSrc: THREE.DstColorFactor,

+ 1 - 0
spine-ts/spine-threejs/src/require-shim.ts

@@ -29,6 +29,7 @@
 
 declare global {
 	var require: any;
+	var THREE: any;
 }
 
 if (typeof window !== 'undefined' && window.THREE) {

+ 3 - 3
spine-ts/spine-threejs/tsconfig.json

@@ -11,11 +11,11 @@
 		}
 	},
 	"include": [
-		"**/*.ts",
-		"src/OrbitControls.js"
+		"**/*.ts"
 	],
 	"exclude": [
-		"dist/**/*.d.ts"
+		"dist/**/*.d.ts",
+		"example/**/*.ts"
 	],
 	"references": [
 		{

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików