'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose');
var _extends = require('@babel/runtime/helpers/extends');
var THREE = require('three');
var React = require('react');
var create = require('zustand');
var shallow = require('zustand/shallow');
var _construct = require('@babel/runtime/helpers/construct');
var Reconciler = require('react-reconciler');
var scheduler = require('scheduler');
var useAsset = require('use-asset');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () {
            return e[k];
          }
        });
      }
    });
  }
  n['default'] = e;
  return Object.freeze(n);
}

var _objectWithoutPropertiesLoose__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutPropertiesLoose);
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
var create__default = /*#__PURE__*/_interopDefaultLegacy(create);
var shallow__default = /*#__PURE__*/_interopDefaultLegacy(shallow);
var _construct__default = /*#__PURE__*/_interopDefaultLegacy(_construct);
var Reconciler__default = /*#__PURE__*/_interopDefaultLegacy(Reconciler);

var name = "react-three-fiber";
var version = "6.0.0-alpha.1";

var is = {
  obj: function obj(a) {
    return a === Object(a) && !is.arr(a);
  },
  fun: function fun(a) {
    return typeof a === 'function';
  },
  str: function str(a) {
    return typeof a === 'string';
  },
  num: function num(a) {
    return typeof a === 'number';
  },
  und: function und(a) {
    return a === void 0;
  },
  arr: function arr(a) {
    return Array.isArray(a);
  },
  equ: function equ(a, b) {
    // Wrong type or one of the two undefined, doesn't match
    if (typeof a !== typeof b || !!a !== !!b) return false; // Atomic, just compare a against b

    if (is.str(a) || is.num(a) || is.obj(a)) return a === b; // Array, shallow compare first to see if it's a match

    if (is.arr(a) && a == b) return true; // Last resort, go through keys

    var i;

    for (i in a) {
      if (!(i in b)) return false;
    }

    for (i in b) {
      if (a[i] !== b[i]) return false;
    }

    return is.und(i) ? a === b : true;
  }
};

var isRenderer = function isRenderer(def) {
  return def && !!def.render;
};
var isOrthographicCamera = function isOrthographicCamera(def) {
  return def && def.isOrthographicCamera;
};
var context = /*#__PURE__*/React.createContext(null);

var createStore = function createStore(applyProps, _invalidate, props) {
  var gl = props.gl,
      size = props.size,
      _props$vr = props.vr,
      vr = _props$vr === void 0 ? false : _props$vr,
      _props$noninteractive = props.noninteractive,
      noninteractive = _props$noninteractive === void 0 ? false : _props$noninteractive,
      _props$shadows = props.shadows,
      shadows = _props$shadows === void 0 ? false : _props$shadows,
      _props$linear = props.linear,
      linear = _props$linear === void 0 ? false : _props$linear,
      _props$orthographic = props.orthographic,
      orthographic = _props$orthographic === void 0 ? false : _props$orthographic,
      _props$frameloop = props.frameloop,
      frameloop = _props$frameloop === void 0 ? true : _props$frameloop,
      _props$updateCamera = props.updateCamera,
      updateCamera = _props$updateCamera === void 0 ? true : _props$updateCamera,
      _props$pixelRatio = props.pixelRatio,
      pixelRatio = _props$pixelRatio === void 0 ? 1 : _props$pixelRatio,
      raycastOptions = props.raycaster,
      cameraOptions = props.camera,
      onCreated = props.onCreated,
      onPointerMissed = props.onPointerMissed; // Set shadowmap

  if (shadows) {
    gl.shadowMap.enabled = true;
    if (typeof shadows === 'object') Object.assign(gl.shadowMap, shadows);else gl.shadowMap.type = THREE.PCFSoftShadowMap;
  } // Set color management


  if (!linear) {
    gl.toneMapping = THREE.ACESFilmicToneMapping;
    gl.outputEncoding = THREE.sRGBEncoding;
  } // Create custom raycaster


  var raycaster = new THREE.Raycaster();
  if (raycastOptions) applyProps(raycaster, raycastOptions, {}); // Create default camera

  var camera = orthographic ? new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE.PerspectiveCamera(75, 0, 0.1, 1000);
  camera.position.z = 5;
  if (cameraOptions) applyProps(camera, cameraOptions, {}); // Always look at [0, 0, 0]

  camera.lookAt(0, 0, 0);
  var scene = new THREE.Scene();
  scene.__r3f = {
    root: {},
    objects: []
  };

  function _setPixelRatio(pixelRatio) {
    return Array.isArray(pixelRatio) ? Math.max(Math.min(pixelRatio[0], window.devicePixelRatio), pixelRatio[1]) : pixelRatio;
  }

  var rootState = create__default['default'](function (set, get) {
    var position = new THREE.Vector3();
    var defaultTarget = new THREE.Vector3();

    function getCurrentViewport(camera, target, size) {
      if (camera === void 0) {
        camera = get().camera;
      }

      if (target === void 0) {
        target = defaultTarget;
      }

      if (size === void 0) {
        size = get().size;
      }

      var _size = size,
          width = _size.width,
          height = _size.height;
      var aspect = width / height;
      var distance = camera.getWorldPosition(position).distanceTo(target);

      if (isOrthographicCamera(camera)) {
        return {
          width: width / camera.zoom,
          height: height / camera.zoom,
          factor: 1,
          distance: distance,
          aspect: aspect
        };
      } else {
        var fov = camera.fov * Math.PI / 180; // convert vertical fov to radians

        var h = 2 * Math.tan(fov / 2) * distance; // visible height

        var w = h * (width / height);
        return {
          width: w,
          height: h,
          factor: width / w,
          distance: distance,
          aspect: aspect
        };
      }
    }

    return {
      gl: gl,
      scene: scene,
      camera: camera,
      raycaster: raycaster,
      mouse: new THREE.Vector2(),
      clock: new THREE.Clock(),
      vr: vr,
      noninteractive: noninteractive,
      linear: linear,
      frameloop: frameloop,
      updateCamera: updateCamera,
      onCreated: onCreated,
      onPointerMissed: onPointerMissed,
      size: {
        width: 0,
        height: 0
      },
      viewport: {
        pixelRatio: 1,
        width: 0,
        height: 0,
        aspect: 0,
        distance: 0,
        factor: 0,
        getCurrentViewport: getCurrentViewport
      },
      invalidate: function invalidate(frames) {
        return _invalidate(get(), frames);
      },
      intersect: function intersect(event) {},
      setSize: function setSize(width, height) {
        var size = {
          width: width,
          height: height
        };
        set(function (state) {
          return {
            size: size,
            viewport: _extends__default['default']({}, state.viewport, getCurrentViewport(camera, defaultTarget, size))
          };
        });
      },
      setCamera: function setCamera(camera) {
        set({
          camera: camera
        });
      },
      setPixelRatio: function setPixelRatio(pixelRatio) {
        set(function (state) {
          return {
            viewport: _extends__default['default']({}, state.viewport, {
              pixelRatio: _setPixelRatio(pixelRatio)
            })
          };
        });
      },
      internal: {
        manual: 0,
        frames: 0,
        lastProps: props,
        interaction: [],
        subscribers: [],
        captured: undefined,
        initialClick: [0, 0],
        initialHits: [],
        set: set,
        subscribe: function subscribe(ref, priority) {
          if (priority === void 0) {
            priority = 0;
          }

          var internal = get().internal; // If this subscription was given a priority, it takes rendering into its own hands
          // For that reason we switch off automatic rendering and increase the manual flag
          // As long as this flag is positive (there could be multiple render subscription)
          // ..there can be no internal rendering at all

          if (priority) internal.manual++;
          internal.subscribers.push({
            ref: ref,
            priority: priority
          }); // Sort layers from lowest to highest, meaning, highest priority renders last (on top of the other frames)

          internal.subscribers = internal.subscribers.sort(function (a, b) {
            return a.priority - b.priority;
          });
          return function () {
            if (internal != null && internal.subscribers) {
              // Decrease manual flag if this subscription had a priority
              if (priority) internal.manual--;
              internal.subscribers = internal.subscribers.filter(function (s) {
                return s.ref !== ref;
              });
            }
          };
        }
      }
    };
  }); // Resize camera and renderer on changes to size and pixelratio

  rootState.subscribe(function () {
    var _rootState$getState = rootState.getState(),
        camera = _rootState$getState.camera,
        size = _rootState$getState.size,
        viewport = _rootState$getState.viewport,
        updateCamera = _rootState$getState.updateCamera; // https://github.com/pmndrs/react-three-fiber/issues/92
    // Sometimes automatic default camera adjustment isn't wanted behaviour


    if (updateCamera) {
      if (isOrthographicCamera(camera)) {
        camera.left = size.width / -2;
        camera.right = size.width / 2;
        camera.top = size.height / 2;
        camera.bottom = size.height / -2;
      } else {
        camera.aspect = size.width / size.height;
      }

      camera.updateProjectionMatrix(); // https://github.com/pmndrs/react-three-fiber/issues/178
      // Update matrix world since the renderer is a frame late

      camera.updateMatrixWorld();
    } // Update renderer


    gl.setPixelRatio(viewport.pixelRatio);
    gl.setSize(size.width, size.height); // Update state model
  }, function (state) {
    return [state.viewport.pixelRatio, state.size];
  }, shallow__default['default']); // Invalidate on any change

  rootState.subscribe(function (state) {
    return _invalidate(state);
  });
  var state = rootState.getState(); // Update pixelratio

  if (pixelRatio) state.setPixelRatio(pixelRatio); // Update size

  if (size) state.setSize(size.width, size.height); // Return root state

  return rootState;
};

var emptyObject = {};
var catalogue = {};

function createRenderer(roots, invalidate) {
  function applyProps(instance, newProps, oldProps, accumulative) {
    var _instance$__r3f, _root$getState;

    if (oldProps === void 0) {
      oldProps = {};
    }

    if (accumulative === void 0) {
      accumulative = false;
    }

    // Filter equals, events and reserved props
    var localState = (_instance$__r3f = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f : {};
    var root = localState.root;
    var rootState = (_root$getState = root == null ? void 0 : root.getState()) != null ? _root$getState : {};
    var sameProps = [];
    var handlers = [];
    var i;
    var keys = Object.keys(newProps);

    for (i = 0; i < keys.length; i++) {
      if (is.equ(newProps[keys[i]], oldProps[keys[i]])) sameProps.push(keys[i]); // Event-handlers ...
      //   are functions, that
      //   start with "on", and
      //   contain the name "Pointer", "Click", "ContextMenu", or "Wheel"

      if (is.fun(newProps[keys[i]]) && keys[i].startsWith('on')) {
        if (keys[i].includes('Pointer') || keys[i].includes('Click') || keys[i].includes('ContextMenu') || keys[i].includes('Wheel')) {
          handlers.push(keys[i]);
        }
      }
    }

    var leftOvers = [];
    keys = Object.keys(oldProps);

    if (accumulative) {
      for (i = 0; i < keys.length; i++) {
        if (newProps[keys[i]] === void 0) {
          leftOvers.push(keys[i]);
        }
      }
    }

    var toFilter = [].concat(sameProps, ['children', 'key', 'ref']); // Instances use "object" as a reserved identifier

    if (localState.instance) toFilter.push('object');

    var filteredProps = _extends__default['default']({}, newProps); // Removes sameProps and reserved props from newProps


    keys = Object.keys(filteredProps);

    for (i = 0; i < keys.length; i++) {
      if (toFilter.indexOf(keys[i]) > -1) {
        delete filteredProps[keys[i]];
      }
    } // Add left-overs as undefined props so they can be removed


    keys = Object.keys(leftOvers);

    for (i = 0; i < keys.length; i++) {
      if (keys[i] !== 'children') {
        filteredProps[keys[i]] = undefined;
      }
    }

    var filteredPropsEntries = Object.entries(filteredProps);

    if (filteredPropsEntries.length > 0) {
      filteredPropsEntries.forEach(function (_ref) {
        var key = _ref[0],
            value = _ref[1];

        if (!handlers.includes(key)) {
          var currentInstance = instance;
          var targetProp = currentInstance[key];

          if (key.includes('-')) {
            var entries = key.split('-');
            targetProp = entries.reduce(function (acc, key) {
              return acc[key];
            }, instance); // If the target is atomic, it forces us to switch the root

            if (!(targetProp && targetProp.set)) {
              var _entries$reverse = entries.reverse(),
                  _name = _entries$reverse[0],
                  reverseEntries = _entries$reverse.slice(1);

              currentInstance = reverseEntries.reverse().reduce(function (acc, key) {
                return acc[key];
              }, instance);
              key = _name;
            }
          } // Special treatment for objects with support for set/copy


          if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE.Layers)) {
            // If value is an array it has got to be the set function
            if (Array.isArray(value)) {
              var _targetProp;

              (_targetProp = targetProp).set.apply(_targetProp, value);
            } // Test again target.copy(class) next ...
            else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) {
                targetProp.copy(value);
              } // If nothing else fits, just set the single value, ignore undefined
              // https://github.com/react-spring/react-three-fiber/issues/274
              else if (value !== undefined) {
                  targetProp.set(value); // Auto-convert sRGB colors, for now ...
                  // https://github.com/react-spring/react-three-fiber/issues/344

                  if (!rootState.linear && targetProp instanceof THREE.Color) targetProp.convertSRGBToLinear();
                } // Else, just overwrite the value

          } else {
            currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
            // https://github.com/react-spring/react-three-fiber/issues/344

            if (!rootState.linear && currentInstance[key] instanceof THREE.Texture) currentInstance[key].encoding = THREE.sRGBEncoding;
          }

          invalidateInstance(instance);
        }
      }); // Preemptively delete the instance from the containers interaction

      if (accumulative && root && instance.raycast && localState.handlers) {
        localState.handlers = undefined;
        var index = rootState.internal.interaction.indexOf(instance);
        if (index > -1) rootState.internal.interaction.splice(index, 1);
      } // Prep interaction handlers


      if (handlers.length) {
        if (accumulative && root && instance.raycast) rootState.internal.interaction.push(instance); // Add handlers to the instances handler-map

        localState.handlers = handlers.reduce(function (acc, key) {
          // @ts-ignore
          acc[key.charAt(2).toLowerCase() + key.substr(3)] = newProps[key];
          return acc;
        }, {});
      } // Call the update lifecycle when it is being updated, but only when it is part of the scene


      if (instance.parent) updateInstance(instance);
    }
  }

  function invalidateInstance(instance) {
    var _instance$__r3f2, _instance$__r3f2$root;

    invalidate((_instance$__r3f2 = instance.__r3f) == null ? void 0 : (_instance$__r3f2$root = _instance$__r3f2.root) == null ? void 0 : _instance$__r3f2$root.getState());
  }

  function updateInstance(instance) {
    if (instance.onUpdate) instance.onUpdate(instance);
  }

  function createInstance(type, _ref2, root) {
    var _ref2$args = _ref2.args,
        args = _ref2$args === void 0 ? [] : _ref2$args,
        props = _objectWithoutPropertiesLoose__default['default'](_ref2, ["args"]);

    var name = "" + type[0].toUpperCase() + type.slice(1);
    var instance; // Bind to the root container in case portals are being used
    // This is perhaps better for event management as we can keep them on a single instance

    /*while ((container as any).__r3f.root) {
      container = (container as any).__r3f.root
    }
     // TODO: https://github.com/facebook/react/issues/17147
    // If it's still not there it means the portal was created on a virtual node outside of react
    if (!roots.has(container)) {
      const fn = (node: Reconciler.Fiber): Container => {
        if (!node.return) return node.stateNode && node.stateNode.containerInfo
        else return fn(node.return)
      }
      container = fn(internalInstanceHandle)
    }*/

    if (type === 'primitive') {
      // Switch off dispose for primitive objects
      props = _extends__default['default']({
        dispose: null
      }, props);
      instance = props.object;
      instance.__r3f = {
        root: root,
        objects: [],
        instance: true,
        dispose: instance.dispose
      };
    } else {
      var target = catalogue[name] || THREE__namespace[name];
      if (!target) throw "\"" + name + "\" is not part of the THREE namespace! Did you forget to extend it? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively"; // Instanciate new object, link it to the root

      instance = is.arr(args) ? _construct__default['default'](target, args) : new target(args);
      instance.__r3f = {
        root: root,
        objects: []
      };
    } // Auto-attach geometries and materials


    if (name.endsWith('Geometry')) {
      props = _extends__default['default']({
        attach: 'geometry'
      }, props);
    } else if (name.endsWith('Material')) {
      props = _extends__default['default']({
        attach: 'material'
      }, props);
    } // It should NOT call onUpdate on object instanciation, because it hasn't been added to the
    // view yet. If the callback relies on references for instance, they won't be ready yet, this is
    // why it passes "true" here


    applyProps(instance, props, {});
    return instance;
  }

  function appendChild(parentInstance, child) {
    if (child) {
      if (child.isObject3D) {
        parentInstance.add(child);
      } else {
        parentInstance.__r3f.objects.push(child);

        child.parent = parentInstance; // The attach attribute implies that the object attaches itself on the parent

        if (child.attachArray) {
          if (!is.arr(parentInstance[child.attachArray])) parentInstance[child.attachArray] = [];
          parentInstance[child.attachArray].push(child);
        } else if (child.attachObject) {
          if (!is.obj(parentInstance[child.attachObject[0]])) parentInstance[child.attachObject[0]] = {};
          parentInstance[child.attachObject[0]][child.attachObject[1]] = child;
        } else if (child.attach) {
          parentInstance[child.attach] = child;
        }
      }

      updateInstance(child);
      invalidateInstance(child);
    }
  }

  function insertBefore(parentInstance, child, beforeChild) {
    if (child) {
      if (child.isObject3D) {
        child.parent = parentInstance;
        child.dispatchEvent({
          type: 'added'
        });
        var restSiblings = parentInstance.children.filter(function (sibling) {
          return sibling !== child;
        }); // TODO: the order is out of whack if data objects are present, has to be recalculated

        var index = restSiblings.indexOf(beforeChild);
        parentInstance.children = [].concat(restSiblings.slice(0, index), [child], restSiblings.slice(index));
        updateInstance(child);
      } else {
        appendChild(parentInstance, child);
      } // TODO: order!!!


      invalidateInstance(child);
    }
  }

  function removeRecursive(array, parent, clone) {
    if (clone === void 0) {
      clone = false;
    }

    if (array) {
      // Three uses splice op's internally we may have to shallow-clone the array in order to safely remove items
      var target = clone ? [].concat(array) : array;
      target.forEach(function (child) {
        return removeChild(parent, child);
      });
    }
  }

  function removeChild(parentInstance, child) {
    if (child) {
      if (child.isObject3D) {
        parentInstance.remove(child);
      } else {
        child.parent = null;
        if (parentInstance.__r3f.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(function (x) {
          return x !== child;
        }); // Remove attachment

        if (child.attachArray) {
          parentInstance[child.attachArray] = parentInstance[child.attachArray].filter(function (x) {
            return x !== child;
          });
        } else if (child.attachObject) {
          delete parentInstance[child.attachObject[0]][child.attachObject[1]];
        } else if (child.attach) {
          parentInstance[child.attach] = null;
        }
      } // Remove interactivity


      if (child.__r3f.root) {
        var rootState = child.__r3f.root.getState();

        rootState.internal.interaction = rootState.internal.interaction.filter(function (x) {
          return x !== child;
        });
      }

      invalidateInstance(parentInstance); // Allow objects to bail out of recursive dispose alltogether by passing dispose={null}

      if (child.dispose !== null) {
        scheduler.unstable_runWithPriority(scheduler.unstable_IdlePriority, function () {
          // Remove nested child objects
          removeRecursive(child.__r3f.objects, child);
          removeRecursive(child.children, child, true); // Dispose item

          if (child.dispose && child.type !== 'Scene') child.dispose();else if (child.__r3f.dispose) child.__r3f.dispose(); // Remove references

          delete child.__r3f.root;
          delete child.__r3f.objects;
          delete child.__r3f.handlers;
          delete child.__r3f.dispose;
          delete child.__r3f;
        });
      }
    }
  }

  function switchInstance(instance, type, newProps, fiber) {
    var parent = instance.parent;
    if (!parent) return;
    var newInstance = createInstance(type, newProps, instance.__r3f.root);
    removeChild(parent, instance);
    appendChild(parent, newInstance) // This evil hack switches the react-internal fiber node
    // https://github.com/facebook/react/issues/14983
    // https://github.com/facebook/react/pull/15021
    ;
    [fiber, fiber.alternate].forEach(function (fiber) {
      if (fiber !== null) {
        fiber.stateNode = newInstance;

        if (fiber.ref) {
          if (typeof fiber.ref === 'function') fiber.ref(newInstance);else fiber.ref.current = newInstance;
        }
      }
    });
  }

  var reconciler = Reconciler__default['default']({
    now: scheduler.unstable_now,
    createInstance: createInstance,
    removeChild: removeChild,
    appendChild: appendChild,
    appendInitialChild: appendChild,
    insertBefore: insertBefore,
    warnsIfNotActing: true,
    supportsMutation: true,
    isPrimaryRenderer: false,
    // @ts-ignore
    scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
    // @ts-ignore
    cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
    // @ts-ignore
    setTimeout: is.fun(setTimeout) ? setTimeout : undefined,
    // @ts-ignore
    clearTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
    noTimeout: -1,
    appendChildToContainer: function appendChildToContainer(parentInstance, child) {
      var scene = parentInstance.getState().scene; // Link current root to the default scene

      scene.__r3f.root = parentInstance;
      appendChild(scene, child);
    },
    removeChildFromContainer: function removeChildFromContainer(parentInstance, child) {
      removeChild(parentInstance.getState().scene, child);
    },
    insertInContainerBefore: function insertInContainerBefore(parentInstance, child, beforeChild) {
      insertBefore(parentInstance.getState().scene, child, beforeChild);
    },
    commitUpdate: function commitUpdate(instance, updatePayload, type, oldProps, newProps, fiber) {
      if (instance.__instance && newProps.object && newProps.object !== instance) {
        // <instance object={...} /> where the object reference has changed
        switchInstance(instance, type, newProps, fiber);
      } else {
        // This is a data object, let's extract critical information about it
        var _newProps$args = newProps.args,
            argsNew = _newProps$args === void 0 ? [] : _newProps$args,
            restNew = _objectWithoutPropertiesLoose__default['default'](newProps, ["args"]);

        var _oldProps$args = oldProps.args,
            argsOld = _oldProps$args === void 0 ? [] : _oldProps$args,
            restOld = _objectWithoutPropertiesLoose__default['default'](oldProps, ["args"]); // If it has new props or arguments, then it needs to be re-instanciated


        var hasNewArgs = argsNew.some(function (value, index) {
          return is.obj(value) ? Object.entries(value).some(function (_ref3) {
            var key = _ref3[0],
                val = _ref3[1];
            return val !== argsOld[index][key];
          }) : value !== argsOld[index];
        });

        if (hasNewArgs) {
          // Next we create a new instance and append it again
          switchInstance(instance, type, newProps, fiber);
        } else {
          // Otherwise just overwrite props
          applyProps(instance, restNew, restOld, true);
        }
      }
    },
    hideInstance: function hideInstance(instance) {
      if (instance.isObject3D) {
        instance.visible = false;
        invalidateInstance(instance);
      }
    },
    // @ts-ignore
    unhideInstance: function unhideInstance(instance, props) {
      if (instance.isObject3D && props.visible == null || props.visible) {
        instance.visible = true;
        invalidateInstance(instance);
      }
    },
    hideTextInstance: function hideTextInstance() {
      throw new Error('Text is not allowed in the react-three-fibre tree. You may have extraneous whitespace between components.');
    },
    getPublicInstance: function getPublicInstance(instance) {
      return instance;
    },
    getRootHostContext: function getRootHostContext() {
      return emptyObject;
    },
    getChildHostContext: function getChildHostContext() {
      return emptyObject;
    },
    createTextInstance: function createTextInstance() {},
    finalizeInitialChildren: function finalizeInitialChildren(instance) {
      // https://github.com/facebook/react/issues/20271
      // Returning true will trigger commitMount
      return !!instance.__r3f.handlers;
    },
    commitMount: function commitMount(instance)
    /*, type, props*/
    {
      // https://github.com/facebook/react/issues/20271
      // This will make sure events are only added once to the central container
      if (instance.raycast && instance.__r3f.handlers) instance.__r3f.root.getState().internal.interaction.push(instance);
    },
    prepareUpdate: function prepareUpdate() {
      return emptyObject;
    },
    shouldDeprioritizeSubtree: function shouldDeprioritizeSubtree() {
      return false;
    },
    prepareForCommit: function prepareForCommit() {
      return null;
    },
    preparePortalMount: function preparePortalMount() {
      return null;
    },
    resetAfterCommit: function resetAfterCommit() {},
    shouldSetTextContent: function shouldSetTextContent() {
      return false;
    },
    clearContainer: function clearContainer() {
      return false;
    }
  });
  return {
    reconciler: reconciler,
    applyProps: applyProps
  };
}

var globalEffects = [];
var globalAfterEffects = [];
var globalTailEffects = [];
function render$1(state, timestamp, repeat, runGlobalEffects) {
  if (repeat === void 0) {
    repeat = 0;
  }

  if (runGlobalEffects === void 0) {
    runGlobalEffects = false;
  }

  var i; // Run global effects

  if (runGlobalEffects) {
    for (i = 0; i < globalEffects.length; i++) {
      globalEffects[i](timestamp);
      repeat++;
    }
  } // Run local effects


  var delta = state.clock.getDelta(); // Call subscribers (useFrame)

  for (i = 0; i < state.internal.subscribers.length; i++) {
    state.internal.subscribers[i].ref.current(state, delta);
  } // Decrease frame count


  state.internal.frames = Math.max(0, state.internal.frames - 1);
  repeat += state.frameloop ? 1 : state.internal.frames; // Render content

  if (!state.internal.manual && state.gl.render) state.gl.render(state.scene, state.camera); // Run global after-effects

  if (runGlobalEffects) for (i = 0; i < globalAfterEffects.length; i++) {
    globalAfterEffects[i](timestamp);
  }
  return repeat;
}

function createLoop(roots) {
  var running = false;

  function loop(timestamp) {
    running = true;
    var i;
    var repeat = 0; // Run global effects

    for (i = 0; i < globalEffects.length; i++) {
      globalEffects[i](timestamp);
      repeat++;
    }

    roots.forEach(function (root) {
      var state = root.store.getState(); // If the frameloop is invalidated, do not run another frame

      repeat = state.frameloop || state.internal.frames > 0 ? render$1(state, timestamp, repeat) : 0;
    }); // Run global after-effects

    for (i = 0; i < globalAfterEffects.length; i++) {
      globalAfterEffects[i](timestamp);
    } // Keep on looping if anything invalidates the frameloop


    if (repeat !== 0) return requestAnimationFrame(loop); // Tail call effects, they are called when rendering stops
    else for (i = 0; i < globalTailEffects.length; i++) {
        globalTailEffects[i](timestamp);
      } // Flag end of operation

    running = false;
  }

  function invalidate(state, frames) {
    if (state === void 0) {
      state = true;
    }

    if (frames === void 0) {
      frames = 1;
    }

    if (state === true) {
      roots.forEach(function (root) {
        return root.store.getState().internal.frames += frames;
      });
    } else if (state) {
      if (state.vr) return;
      state.internal.frames += frames;
    }

    if (!running) {
      running = true;
      requestAnimationFrame(loop);
    }
  }

  return {
    loop: loop,
    invalidate: invalidate
  };
}

function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var makeId = function makeId(event) {
  return (event.eventObject || event.object).uuid + '/' + event.index;
};

function createEvents(store) {
  var hovered = new Map();
  var temp = new THREE.Vector3();
  /** Sets up defaultRaycaster */

  function prepareRay(event) {
    var _internal$lastProps$r;

    var state = store.getState();
    var raycaster = state.raycaster,
        mouse = state.mouse,
        camera = state.camera,
        size = state.size,
        internal = state.internal; // https://github.com/pmndrs/react-three-fiber/pull/782
    // Events trigger outside of canvas when moved

    var offsets = ((_internal$lastProps$r = internal.lastProps.raycaster) == null ? void 0 : _internal$lastProps$r.computeOffsets == null ? void 0 : _internal$lastProps$r.computeOffsets(event, state)) || event;

    if (offsets) {
      var offsetX = offsets.offsetX,
          offsetY = offsets.offsetY;
      var width = size.width,
          height = size.height;
      mouse.set(offsetX / width * 2 - 1, -(offsetY / height) * 2 + 1);
      raycaster.setFromCamera(mouse, camera);
    }
  }
  /** Intersects interaction objects using the event input */


  function intersect(filter) {
    var _internal$lastProps, _internal$lastProps$r2;

    var state = store.getState();
    var raycaster = state.raycaster,
        noninteractive = state.noninteractive,
        internal = state.internal; // Skip event handling when noEvents is set

    if (noninteractive) return [];
    var seen = new Set();
    var hits = []; // Allow callers to eliminate event objects

    var eventsObjects = filter ? filter(internal.interaction) : internal.interaction; // Intersect known handler objects and filter against duplicates

    var intersects = raycaster.intersectObjects(eventsObjects, true).filter(function (item) {
      var id = makeId(item);
      if (seen.has(id)) return false;
      seen.add(id);
      return true;
    }); // https://github.com/mrdoob/three.js/issues/16031
    // Allow custom userland intersect sort order

    if ((_internal$lastProps = internal.lastProps) != null && (_internal$lastProps$r2 = _internal$lastProps.raycaster) != null && _internal$lastProps$r2.filter) intersects = internal.lastProps.raycaster.filter(intersects, state);

    for (var _iterator = _createForOfIteratorHelperLoose(intersects), _step; !(_step = _iterator()).done;) {
      var _intersect = _step.value;
      var eventObject = _intersect.object; // Bubble event up

      while (eventObject) {
        var handlers = eventObject.__r3f.handlers;
        if (handlers) hits.push(_extends__default['default']({}, _intersect, {
          eventObject: eventObject
        }));
        eventObject = eventObject.parent;
      }
    }

    return hits;
  }
  /**  Calculates click deltas */


  function calculateDistance(event) {
    var _store$getState = store.getState(),
        internal = _store$getState.internal;

    var dx = event.offsetX - internal.initialClick[0];
    var dy = event.offsetY - internal.initialClick[1];
    return Math.round(Math.sqrt(dx * dx + dy * dy));
  }

  function handlePointerCancel(event, hits, prepare) {
    if (prepare === void 0) {
      prepare = true;
    }

    if (prepare) prepareRay(event);
    Array.from(hovered.values()).forEach(function (hoveredObj) {
      // When no objects were hit or the the hovered object wasn't found underneath the cursor
      // we call onPointerOut and delete the object from the hovered-elements map
      if (hits && (!hits.length || !hits.find(function (hit) {
        return hit.object === hoveredObj.object && hit.index === hoveredObj.index;
      }))) {
        var eventObject = hoveredObj.eventObject;
        var handlers = eventObject.__r3f.handlers;
        hovered["delete"](makeId(hoveredObj));

        if (handlers) {
          // Clear out intersects, they are outdated by now
          var data = _extends__default['default']({}, hoveredObj, {
            intersections: hits || []
          });

          if (handlers.pointerOut) handlers.pointerOut(_extends__default['default']({}, data, {
            type: 'pointerout'
          }));
          if (handlers.pointerLeave) handlers.pointerLeave(_extends__default['default']({}, data, {
            type: 'pointerleave'
          }));
        }
      }
    });
  }
  /**  Creates filtered intersects and returns an array of positive hits */


  function getIntersects(event, filter) {
    var _store$getState2 = store.getState(),
        internal = _store$getState2.internal; // Get fresh intersects


    var intersections = intersect(filter); // If the interaction is captured take that into account, the captured event has to be part of the intersects

    if (internal.captured && event.type !== 'click' && event.type !== 'wheel') {
      internal.captured.forEach(function (captured) {
        if (!intersections.find(function (hit) {
          return hit.eventObject === captured.eventObject;
        })) intersections.push(captured);
      });
    }

    return intersections;
  }
  /**  Handles intersections by forwarding them to handlers */


  function handleIntersects(intersections, event, fn) {
    var _store$getState3 = store.getState(),
        raycaster = _store$getState3.raycaster,
        mouse = _store$getState3.mouse,
        camera = _store$getState3.camera,
        internal = _store$getState3.internal; // If anything has been found, forward it to the event listeners


    if (intersections.length) {
      (function () {
        var unprojectedPoint = temp.set(mouse.x, mouse.y, 0).unproject(camera);
        var delta = event.type === 'click' ? calculateDistance(event) : 0;

        var releasePointerCapture = function releasePointerCapture(id) {
          return event.target.releasePointerCapture(id);
        };

        var localState = {
          stopped: false,
          captured: false
        };

        var _loop = function _loop() {
          var hit = _step2.value;

          var setPointerCapture = function setPointerCapture(id) {
            // If the hit is going to be captured flag that we're in captured state
            if (!localState.captured) {
              localState.captured = true; // The captured hit array is reset to collect hits

              internal.captured = [];
            } // Push hits to the array


            if (internal.captured) internal.captured.push(hit) // Call the original event now
            ;
            event.target.setPointerCapture(id);
          };

          var raycastEvent = _extends__default['default']({}, event, hit, {
            intersections: intersections,
            stopped: localState.stopped,
            delta: delta,
            unprojectedPoint: unprojectedPoint,
            ray: raycaster.ray,
            camera: camera,
            // Hijack stopPropagation, which just sets a flag
            stopPropagation: function stopPropagation() {
              // https://github.com/react-spring/react-three-fiber/issues/596
              // Events are not allowed to stop propagation if the pointer has been captured
              var cap = internal.captured;

              if (!cap || cap.find(function (h) {
                return h.eventObject.id === hit.eventObject.id;
              })) {
                raycastEvent.stopped = localState.stopped = true; // Propagation is stopped, remove all other hover records
                // An event handler is only allowed to flush other handlers if it is hovered itself

                if (hovered.size && Array.from(hovered.values()).find(function (i) {
                  return i.eventObject === hit.eventObject;
                })) {
                  // Objects cannot flush out higher up objects that have already caught the event
                  var higher = intersections.slice(0, intersections.indexOf(hit));
                  handlePointerCancel(raycastEvent, [].concat(higher, [hit]));
                }
              }
            },
            target: _extends__default['default']({}, event.target, {
              setPointerCapture: setPointerCapture,
              releasePointerCapture: releasePointerCapture
            }),
            currentTarget: _extends__default['default']({}, event.currentTarget, {
              setPointerCapture: setPointerCapture,
              releasePointerCapture: releasePointerCapture
            }),
            sourceEvent: event
          });

          fn(raycastEvent); // Event bubbling may be interrupted by stopPropagation

          if (localState.stopped === true) return "break";
        };

        for (var _iterator2 = _createForOfIteratorHelperLoose(intersections), _step2; !(_step2 = _iterator2()).done;) {
          var _ret = _loop();

          if (_ret === "break") break;
        }
      })();
    }

    return intersections;
  }

  function handlePointerMove(event, prepare) {
    if (prepare === void 0) {
      prepare = true;
    }

    if (prepare) prepareRay(event);
    var hits = getIntersects(event, // This is onPointerMove, we're only interested in events that exhibit this particular event
    function (objects) {
      return objects.filter(function (obj) {
        return ['Move', 'Over', 'Enter', 'Out', 'Leave'].some(function (name) {
          return obj.__r3f.handlers['pointer' + name];
        });
      });
    }); // Take care of unhover

    handlePointerCancel(event, hits);
    handleIntersects(hits, event, function (data) {
      var eventObject = data.eventObject;
      var handlers = eventObject.__r3f.handlers; // Check presence of handlers

      if (!handlers) return; // Check if mouse enter or out is present

      if (handlers.pointerOver || handlers.pointerEnter || handlers.pointerOut || handlers.pointerLeave) {
        var id = makeId(data);
        var hoveredItem = hovered.get(id);

        if (!hoveredItem) {
          // If the object wasn't previously hovered, book it and call its handler
          hovered.set(id, data);
          if (handlers.pointerOver) handlers.pointerOver(_extends__default['default']({}, data, {
            type: 'pointerover'
          }));
          if (handlers.pointerEnter) handlers.pointerEnter(_extends__default['default']({}, data, {
            type: 'pointerenter'
          }));
        } else if (hoveredItem.stopped) {
          // If the object was previously hovered and stopped, we shouldn't allow other items to proceed
          data.stopPropagation();
        }
      } // Call mouse move


      if (handlers.pointerMove) handlers.pointerMove(data);
    });
    return hits;
  }

  function pointerMissed(event, objects, filter) {
    if (filter === void 0) {
      filter = function filter(object) {
        return true;
      };
    }

    objects.filter(filter).forEach(function (object) {
      var _r3f$handlers$pointe, _r3f$handlers;

      return (_r3f$handlers$pointe = (_r3f$handlers = object.__r3f.handlers).pointerMissed) == null ? void 0 : _r3f$handlers$pointe.call(_r3f$handlers, event);
    });
  }

  var handlePointer = function handlePointer(name) {
    return function (event, prepare) {
      if (prepare === void 0) {
        prepare = true;
      }

      var _store$getState4 = store.getState(),
          onPointerMissed = _store$getState4.onPointerMissed,
          internal = _store$getState4.internal;

      if (prepare) prepareRay(event);
      var hits = getIntersects(event);
      handleIntersects(hits, event, function (data) {
        var eventObject = data.eventObject;
        var handlers = eventObject.__r3f.handlers;

        if (handlers && handlers[name]) {
          // Forward all events back to their respective handlers with the exception of click events,
          // which must use the initial target
          if (name !== 'click' && name !== 'contextMenu' && name !== 'doubleClick' || internal.initialHits.includes(eventObject)) {
            handlers[name](data);
            pointerMissed(event, internal.interaction, function (object) {
              return object !== eventObject;
            });
          }
        }
      }); // If a click yields no results, pass it back to the user as a miss

      if (name === 'pointerDown') {
        internal.initialClick = [event.offsetX, event.offsetY];
        internal.initialHits = hits.map(function (hit) {
          return hit.eventObject;
        });
      }

      if ((name === 'click' || name === 'contextMenu' || name === 'doubleClick') && !hits.length) {
        if (calculateDistance(event) <= 2) {
          pointerMissed(event, internal.interaction);
          if (onPointerMissed) onPointerMissed();
        }
      }
    };
  };

  return {
    onClick: handlePointer('click'),
    onContextMenu: handlePointer('contextMenu'),
    onDoubleClick: handlePointer('doubleClick'),
    onWheel: handlePointer('wheel'),
    onPointerDown: handlePointer('pointerDown'),
    onPointerUp: handlePointer('pointerUp'),
    onPointerLeave: function onPointerLeave(e) {
      return handlePointerCancel(e, []);
    },
    onPointerMove: handlePointerMove,
    onLostPointerCapture: function onLostPointerCapture(e) {
      return store.getState().internal.captured = undefined, handlePointerCancel(e);
    }
  };
}

function Canvas() {
  return null;
}

function useThree(selector, equalityFn) {
  return React.useContext(context)(selector, equalityFn);
}
function useFrame(callback, renderPriority) {
  if (renderPriority === void 0) {
    renderPriority = 0;
  }

  var subscribe = React.useContext(context).getState().internal.subscribe; // Update ref

  var ref = React.useRef(callback);
  React.useLayoutEffect(function () {
    return void (ref.current = callback);
  }, [callback]); // Subscribe/unsub

  React.useEffect(function () {
    var unsubscribe = subscribe(ref, renderPriority);
    return function () {
      return unsubscribe();
    };
  }, [renderPriority, subscribe]);
  return null;
}
function useUpdate(callback, dependents, optionalRef) {
  var _React$useContext$get = React.useContext(context).getState(),
      invalidate = _React$useContext$get.invalidate;

  var localRef = React.useRef();
  var ref = optionalRef ? optionalRef : localRef;
  React.useLayoutEffect(function () {
    if (ref.current) {
      callback(ref.current);
      invalidate();
    }
  }, dependents); // eslint-disable-line react-hooks/exhaustive-deps

  return ref;
}
function useResource(optionalRef) {
  var _React$useState = React.useState(false);
      _React$useState[0];
      var forceUpdate = _React$useState[1];

  var localRef = React.useRef(undefined);
  var ref = optionalRef ? optionalRef : localRef;
  React.useLayoutEffect(function () {
    return void forceUpdate(function (i) {
      return !i;
    });
  }, []);
  return ref;
}

function buildGraph(object) {
  var data = {
    nodes: {},
    materials: {}
  };

  if (object) {
    object.traverse(function (obj) {
      if (obj.name) data.nodes[obj.name] = obj;
      if (obj.material && !data.materials[obj.material.name]) data.materials[obj.material.name] = obj.material;
    });
  }

  return data;
}

function useGraph(object) {
  return React.useMemo(function () {
    return buildGraph(object);
  }, [object]);
}

function loadingFn(extensions, onProgress) {
  return function (Proto) {
    // Construct new loader and run extensions
    var loader = new Proto();
    if (extensions) extensions(loader); // Go through the urls and load them

    for (var _len = arguments.length, input = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      input[_key - 1] = arguments[_key];
    }

    return Promise.all(input.map(function (input) {
      return new Promise(function (res, reject) {
        return loader.load(input, function (data) {
          if (data.scene) Object.assign(data, buildGraph(data.scene));
          res(data);
        }, onProgress, function (error) {
          var _error$message;

          return reject((_error$message = error.message) != null ? _error$message : "failure loading " + input);
        });
      });
    }));
  };
}

function useLoader(Proto, input, extensions, onProgress) {
  // Use suspense to load async assets
  var keys = Array.isArray(input) ? input : [input];
  var results = useAsset.useAsset.apply(void 0, [loadingFn(extensions, onProgress), Proto].concat(keys)); // Return the object/s

  return Array.isArray(input) ? results : results[0];
}

useLoader.preload = function (Proto, input, extensions) {
  var keys = Array.isArray(input) ? input : [input];
  return useAsset.useAsset.preload.apply(useAsset.useAsset, [loadingFn(extensions), Proto].concat(keys));
};

var roots = new Map();

var _createLoop = createLoop(roots),
    invalidate = _createLoop.invalidate;

var _createRenderer = createRenderer(roots, invalidate),
    reconciler = _createRenderer.reconciler,
    applyProps = _createRenderer.applyProps;

var createRendererInstance = function createRendererInstance(gl, canvas) {
  return isRenderer(gl) ? gl : new THREE.WebGLRenderer(_extends__default['default']({
    powerPreference: 'high-performance',
    canvas: canvas,
    antialias: true,
    alpha: true
  }, gl));
};

function render(element, canvas, _ref) {
  var _store;

  var gl = _ref.gl,
      size = _ref.size,
      concurrent = _ref.concurrent,
      props = _objectWithoutPropertiesLoose__default['default'](_ref, ["gl", "size", "concurrent"]);

  var root = roots.get(canvas);
  var fiber = root == null ? void 0 : root.fiber;
  var store = root == null ? void 0 : root.store;
  var state = (_store = store) == null ? void 0 : _store.getState();

  if (fiber && state) {
    var lastProps = state.internal.lastProps; // When a root was found, see if any fundamental props must be changed or exchanged
    // Check pixelratio

    if (props.pixelRatio !== undefined && !is.equ(lastProps.pixelRatio, props.pixelRatio)) state.setPixelRatio(props.pixelRatio); // Check size

    if (size !== undefined && !is.equ(lastProps.size, size)) state.setSize(size.width, size.height); // For some props we want to reset the entire root
    // Changes to the color-space

    var linearChanged = props.linear !== lastProps.linear;

    if (linearChanged) {
      unmountComponentAtNode(canvas);
      fiber = undefined;
    }
  }

  if (!fiber) {
    // If no root has been found, make one
    store = createStore(applyProps, invalidate, _extends__default['default']({
      gl: createRendererInstance(gl, canvas),
      size: size
    }, props));
    var events = createEvents(store);
    canvas.addEventListener('pointermove', function (e) {
      return events.onPointerMove(e);
    }, {
      passive: true
    });
    canvas.addEventListener('pointerdown', function (e) {
      return events.onPointerDown(e);
    }, {
      passive: true
    });
    canvas.addEventListener('pointerup', function (e) {
      return events.onPointerUp(e);
    }, {
      passive: true
    });
    canvas.addEventListener('pointerleave', function (e) {
      return events.onPointerLeave(e);
    }, {
      passive: true
    });
    canvas.addEventListener('click', function (e) {
      return events.onClick(e);
    }, {
      passive: true
    });
    fiber = reconciler.createContainer(store, concurrent ? 2 : 0, false, null); // Map it

    roots.set(canvas, {
      fiber: fiber,
      store: store
    }); // Kick off render loop

    store.getState().invalidate();
  }

  if (store && fiber) {
    reconciler.updateContainer( /*#__PURE__*/React.createElement(context.Provider, {
      value: store,
      children: element
    }), fiber, null, function () {
      return undefined;
    });
    return reconciler.getPublicRootInstance(fiber);
  } else {
    throw 'R3F: Error creating fiber-root!';
  }
}

function unmountComponentAtNode(canvas, callback) {
  var root = roots.get(canvas);
  var fiber = root == null ? void 0 : root.fiber;

  if (fiber) {
    reconciler.updateContainer(null, fiber, null, function () {
      var state = root == null ? void 0 : root.store.getState();

      if (state) {
        if (state.gl.renderLists) state.gl.renderLists.dispose();
        if (state.gl.forceContextLoss) state.gl.forceContextLoss();
        dispose(state.gl);
        dispose(state.raycaster);
        dispose(state.camera);
        dispose(state);
      }

      roots["delete"](canvas);
      if (callback) callback(canvas);
    });
  }
}

function dispose(obj) {
  if (obj.dispose && obj.type !== 'Scene') obj.dispose();

  for (var p in obj) {
    if (typeof p === 'object' && p.dispose) p.dispose();
    delete obj[p];
  }
}

var hasSymbol = is.fun(Symbol) && Symbol["for"];
var REACT_PORTAL_TYPE = hasSymbol ? Symbol["for"]('react.portal') : 0xeaca;

function createPortal(children, container, impl, key) {
  if (key === void 0) {
    key = null;
  }

  if (!container.__objects) container.__objects = [];
  return {
    $$typeof: REACT_PORTAL_TYPE,
    key: key == null ? null : '' + key,
    children: children,
    container: container,
    impl: impl
  };
}

reconciler.injectIntoDevTools({
  bundleType: process.env.NODE_ENV === 'production' ? 0 : 1,
  rendererPackageName: name,
  version: version
});

exports.Canvas = Canvas;
exports.applyProps = applyProps;
exports.context = context;
exports.createPortal = createPortal;
exports.invalidate = invalidate;
exports.reconciler = reconciler;
exports.render = render;
exports.unmountComponentAtNode = unmountComponentAtNode;
exports.useFrame = useFrame;
exports.useGraph = useGraph;
exports.useLoader = useLoader;
exports.useResource = useResource;
exports.useThree = useThree;
exports.useUpdate = useUpdate;
