<!-- NEW4 — TEST 4 · THE QUILT · part 425 -->
mationLoop = function ( callback ) {

			onAnimationFrameCallback = callback;
			xr.setAnimationLoop( callback );

			( callback === null ) ? animation.stop() : animation.start();

		};

		xr.addEventListener( 'sessionstart', onXRSessionStart );
		xr.addEventListener( 'sessionend', onXRSessionEnd );

		// Rendering

		/**
		 * Renders the given scene (or other type of 3D object) using the given camera.
		 *
		 * The render is done to a previously specified render target set by calling {@link WebGLRenderer#setRenderTarget}
		 * or to the canvas as usual.
		 *
		 * By default render buffers are cleared before rendering but you can prevent
		 * this by setting the property `autoClear` to `false`. If you want to prevent
		 * only certain buffers being cleared you can `autoClearColor`, `autoClearDepth`
		 * or `autoClearStencil` to `false`. To force a clear, use {@link WebGLRenderer#clear}.
		 *
		 * @param {Object3D} scene - The scene to render.
		 * @param {Camera} camera - The camera.
		 */
		this.render = function ( scene, camera ) {

			if ( camera !== undefined && camera.isCamera !== true ) {

				error( 'WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
				return;

			}

			if ( _isContextLost === true ) return;

			// update node builder if available
			if ( _nodesHandler !== null ) {

				_nodesHandler.renderStart( scene, camera );

			}

			// use internal render target for HalfFloatType color buffer (only when tone mapping is enabled)

			const isXRPresenting = xr.enabled === true && xr.isPresenting === true;

			const useOutput = output !== null && ( _currentRenderTarget === null || isXRPresenting ) && output.begin( _this, _currentRenderTarget );

			// update scene graph

			if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

			// update camera matrices and frustum

			if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

			if ( xr.enabled === true && xr.isPresenting === true && ( output === null || output.isCompositing() === false ) ) {

				if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );

				camera = xr.getCamera(); // use XR camera for rendering

			}

			//
			if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );

			currentRenderState = renderStates.get( scene, renderStateStack.length );
			currentRenderState.init( camera );

			currentRenderState.state.textureUnits = textures.getTextureUnits();
			renderStateStack.push( currentRenderState );

			_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
			_frustum.setFromProjectionMatrix( _projScreenMatrix, WebGLCoordinateSystem, camera.reversedDepth );

			_localClippingEnabled = this.localClippingEnabled;
			_clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );

			currentRenderList = renderLists.get( scene, renderListStack.length );
			currentRenderList.init();

			renderListStack.push( currentRenderList );

			if ( xr.enabled === true && xr.isPresenting === true ) {

				const depthSensingMesh = _this.xr.getDepthSensingMesh();

				if ( depthSensingMesh !== null ) {

					projectObject( depthSensingMesh, camera, - Infinity, _this.sortObjects );

				}

			}

			projectObject( scene, camera, 0, _this.sortObjects );

			currentRenderList.finish();
			if ( _nodesHandler !== null ) _nodesHandler.updateLights( currentRenderState.state.lightsArray );

			if ( _this.sortObjects === true ) {

				currentRenderList.sort( _opaqueSort, _transparentSort );

			}

			_renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false;
			if ( _renderBackground ) {

				background.addToRenderList( currentRenderList, scene );

			}

			//

			this.info.render.frame ++;

			if ( this.info.autoReset === true ) this.info.reset();

			if ( _clippingEnabled === true ) clipping.beginShadows();

			const shadowsArray = currentRenderState.state.shadowsArray;

			shadowMap.render( shadowsArray, scene, camera );

			if ( _clippingEnabled === true ) clipping.endShadows();

			//

			// render scene (skip if first effect is a render pass - it will render the scene itself)

			const skipSceneRender = useOutput && output.hasRenderPass();

			if ( skipSceneRender === false ) {

				const opaqueObjects = currentRenderList.opaque;
				const transmissiveObjects = currentRenderList.transmissive;

				currentRenderState.setupLights();

				if ( camera.isArrayCamera ) {

					const cameras = camera.cameras;

					if ( transmissiveObjects.length > 0 ) {

						for ( let i = 0, l = cameras.length; i < l; i ++ ) {

							const camera2 = cameras[ i ];

							renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera2 );

						}

					}

					if ( _renderBackground ) background.render( scene );

					for ( let i = 0, l = cameras.length; i < l; i ++ ) {

						const camera2 = ca