@react-three/fiber 8.2.3 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,11 @@
1
- import * as React from 'react';
2
- import type { Options as ResizeOptions } from 'react-use-measure';
3
- import { RenderProps } from '../core';
4
- export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
- children: React.ReactNode;
6
- fallback?: React.ReactNode;
7
- resize?: ResizeOptions;
8
- }
9
- export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
1
+ import * as React from 'react';
2
+ import type { Options as ResizeOptions } from 'react-use-measure';
3
+ import { RenderProps } from '../core';
4
+ export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ fallback?: React.ReactNode;
7
+ resize?: ResizeOptions;
8
+ eventTarget?: HTMLElement;
9
+ eventPrefix?: 'offset' | 'client' | 'page' | 'layer' | 'screen';
10
+ }
11
+ export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
@@ -1,4 +1,4 @@
1
- import { UseBoundStore } from 'zustand';
2
- import { RootState } from '../core/store';
3
- import { EventManager } from '../core/events';
4
- export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
1
+ import { UseBoundStore } from 'zustand';
2
+ import { RootState } from '../core/store';
3
+ import { EventManager } from '../core/events';
4
+ export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
@@ -45,8 +45,8 @@ class ErrorBoundary extends React.Component {
45
45
  };
46
46
  }
47
47
 
48
- componentDidCatch(error) {
49
- this.props.set(error);
48
+ componentDidCatch(err) {
49
+ this.props.set(err);
50
50
  }
51
51
 
52
52
  render() {
@@ -849,7 +849,7 @@ function createRenderer(_roots, _getEventPriority) {
849
849
  }
850
850
 
851
851
  if (type === 'primitive') {
852
- if (props.object === undefined) throw `Primitives without 'object' are invalid!`;
852
+ if (props.object === undefined) throw new Error("R3F: Primitives without 'object' are invalid!");
853
853
  const object = props.object;
854
854
  instance = prepare(object, {
855
855
  type,
@@ -861,11 +861,11 @@ function createRenderer(_roots, _getEventPriority) {
861
861
  const target = catalogue[name];
862
862
 
863
863
  if (!target) {
864
- throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`;
864
+ throw new Error(`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`);
865
865
  } // Throw if an object or literal was passed for args
866
866
 
867
867
 
868
- if (!Array.isArray(args)) throw 'The args prop must be an array!'; // Instanciate new object, link it to the root
868
+ if (!Array.isArray(args)) throw new Error('R3F: The args prop must be an array!'); // Instanciate new object, link it to the root
869
869
  // Append memoized props with args so it's not forgotten
870
870
 
871
871
  instance = prepare(new target(...args), {
@@ -1103,7 +1103,7 @@ function createRenderer(_roots, _getEventPriority) {
1103
1103
  ...restOld
1104
1104
  } = oldProps; // Throw if an object or literal was passed for args
1105
1105
 
1106
- if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instantiated
1106
+ if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!'); // If it has new props or arguments, then it needs to be re-instantiated
1107
1107
 
1108
1108
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
1109
1109
 
@@ -1566,7 +1566,7 @@ function createLoop(roots) {
1566
1566
 
1567
1567
  function useStore() {
1568
1568
  const store = React.useContext(context);
1569
- if (!store) throw `R3F hooks can only be used within the Canvas component!`;
1569
+ if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
1570
1570
  return store;
1571
1571
  }
1572
1572
  /**
@@ -1610,7 +1610,7 @@ function loadingFn(extensions, onProgress) {
1610
1610
  return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
1611
1611
  if (data.scene) Object.assign(data, buildGraph(data.scene));
1612
1612
  res(data);
1613
- }, onProgress, error => reject(`Could not load ${input}: ${error.message}`)))));
1613
+ }, onProgress, error => reject(new Error(`Could not load ${input}: ${error.message})`))))));
1614
1614
  };
1615
1615
  }
1616
1616
  /**
@@ -72,8 +72,8 @@ class ErrorBoundary extends React__namespace.Component {
72
72
  };
73
73
  }
74
74
 
75
- componentDidCatch(error) {
76
- this.props.set(error);
75
+ componentDidCatch(err) {
76
+ this.props.set(err);
77
77
  }
78
78
 
79
79
  render() {
@@ -876,7 +876,7 @@ function createRenderer(_roots, _getEventPriority) {
876
876
  }
877
877
 
878
878
  if (type === 'primitive') {
879
- if (props.object === undefined) throw `Primitives without 'object' are invalid!`;
879
+ if (props.object === undefined) throw new Error("R3F: Primitives without 'object' are invalid!");
880
880
  const object = props.object;
881
881
  instance = prepare(object, {
882
882
  type,
@@ -888,11 +888,11 @@ function createRenderer(_roots, _getEventPriority) {
888
888
  const target = catalogue[name];
889
889
 
890
890
  if (!target) {
891
- throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`;
891
+ throw new Error(`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`);
892
892
  } // Throw if an object or literal was passed for args
893
893
 
894
894
 
895
- if (!Array.isArray(args)) throw 'The args prop must be an array!'; // Instanciate new object, link it to the root
895
+ if (!Array.isArray(args)) throw new Error('R3F: The args prop must be an array!'); // Instanciate new object, link it to the root
896
896
  // Append memoized props with args so it's not forgotten
897
897
 
898
898
  instance = prepare(new target(...args), {
@@ -1130,7 +1130,7 @@ function createRenderer(_roots, _getEventPriority) {
1130
1130
  ...restOld
1131
1131
  } = oldProps; // Throw if an object or literal was passed for args
1132
1132
 
1133
- if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instantiated
1133
+ if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!'); // If it has new props or arguments, then it needs to be re-instantiated
1134
1134
 
1135
1135
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
1136
1136
 
@@ -1593,7 +1593,7 @@ function createLoop(roots) {
1593
1593
 
1594
1594
  function useStore() {
1595
1595
  const store = React__namespace.useContext(context);
1596
- if (!store) throw `R3F hooks can only be used within the Canvas component!`;
1596
+ if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
1597
1597
  return store;
1598
1598
  }
1599
1599
  /**
@@ -1637,7 +1637,7 @@ function loadingFn(extensions, onProgress) {
1637
1637
  return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
1638
1638
  if (data.scene) Object.assign(data, buildGraph(data.scene));
1639
1639
  res(data);
1640
- }, onProgress, error => reject(`Could not load ${input}: ${error.message}`)))));
1640
+ }, onProgress, error => reject(new Error(`Could not load ${input}: ${error.message})`))))));
1641
1641
  };
1642
1642
  }
1643
1643
  /**
@@ -72,8 +72,8 @@ class ErrorBoundary extends React__namespace.Component {
72
72
  };
73
73
  }
74
74
 
75
- componentDidCatch(error) {
76
- this.props.set(error);
75
+ componentDidCatch(err) {
76
+ this.props.set(err);
77
77
  }
78
78
 
79
79
  render() {
@@ -876,7 +876,7 @@ function createRenderer(_roots, _getEventPriority) {
876
876
  }
877
877
 
878
878
  if (type === 'primitive') {
879
- if (props.object === undefined) throw `Primitives without 'object' are invalid!`;
879
+ if (props.object === undefined) throw new Error("R3F: Primitives without 'object' are invalid!");
880
880
  const object = props.object;
881
881
  instance = prepare(object, {
882
882
  type,
@@ -888,11 +888,11 @@ function createRenderer(_roots, _getEventPriority) {
888
888
  const target = catalogue[name];
889
889
 
890
890
  if (!target) {
891
- throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`;
891
+ throw new Error(`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`);
892
892
  } // Throw if an object or literal was passed for args
893
893
 
894
894
 
895
- if (!Array.isArray(args)) throw 'The args prop must be an array!'; // Instanciate new object, link it to the root
895
+ if (!Array.isArray(args)) throw new Error('R3F: The args prop must be an array!'); // Instanciate new object, link it to the root
896
896
  // Append memoized props with args so it's not forgotten
897
897
 
898
898
  instance = prepare(new target(...args), {
@@ -1130,7 +1130,7 @@ function createRenderer(_roots, _getEventPriority) {
1130
1130
  ...restOld
1131
1131
  } = oldProps; // Throw if an object or literal was passed for args
1132
1132
 
1133
- if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instantiated
1133
+ if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!'); // If it has new props or arguments, then it needs to be re-instantiated
1134
1134
 
1135
1135
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
1136
1136
 
@@ -1593,7 +1593,7 @@ function createLoop(roots) {
1593
1593
 
1594
1594
  function useStore() {
1595
1595
  const store = React__namespace.useContext(context);
1596
- if (!store) throw `R3F hooks can only be used within the Canvas component!`;
1596
+ if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
1597
1597
  return store;
1598
1598
  }
1599
1599
  /**
@@ -1637,7 +1637,7 @@ function loadingFn(extensions, onProgress) {
1637
1637
  return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
1638
1638
  if (data.scene) Object.assign(data, buildGraph(data.scene));
1639
1639
  res(data);
1640
- }, onProgress, error => reject(`Could not load ${input}: ${error.message}`)))));
1640
+ }, onProgress, error => reject(new Error(`Could not load ${input}: ${error.message})`))))));
1641
1641
  };
1642
1642
  }
1643
1643
  /**
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('./index-942a305b.cjs.dev.js');
5
+ var index = require('./index-bcd3e47c.cjs.dev.js');
6
6
  var _extends = require('@babel/runtime/helpers/extends');
7
7
  var React = require('react');
8
8
  var THREE = require('three');
@@ -126,6 +126,8 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(function Canvas({
126
126
  style,
127
127
  gl,
128
128
  events = createPointerEvents,
129
+ eventTarget,
130
+ eventPrefix,
129
131
  shadows,
130
132
  linear,
131
133
  flat,
@@ -184,7 +186,21 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(function Canvas({
184
186
  // Pass mutable reference to onPointerMissed so it's free to update
185
187
  onPointerMissed: (...args) => handlePointerMissed.current == null ? void 0 : handlePointerMissed.current(...args),
186
188
  onCreated: state => {
187
- state.events.connect == null ? void 0 : state.events.connect(divRef.current);
189
+ // Connect to event source
190
+ state.events.connect == null ? void 0 : state.events.connect(eventTarget ? eventTarget : divRef.current); // Set up compute function
191
+
192
+ if (eventPrefix) {
193
+ state.setEvents({
194
+ compute: (event, state) => {
195
+ const x = event[eventPrefix + 'X'];
196
+ const y = event[eventPrefix + 'Y'];
197
+ state.pointer.set(x / state.size.width * 2 - 1, -(y / state.size.height) * 2 + 1);
198
+ state.raycaster.setFromCamera(state.pointer, state.camera);
199
+ }
200
+ });
201
+ } // Call onCreated callback
202
+
203
+
188
204
  onCreated == null ? void 0 : onCreated(state);
189
205
  }
190
206
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('./index-1be7d4d7.cjs.prod.js');
5
+ var index = require('./index-e086bd20.cjs.prod.js');
6
6
  var _extends = require('@babel/runtime/helpers/extends');
7
7
  var React = require('react');
8
8
  var THREE = require('three');
@@ -126,6 +126,8 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(function Canvas({
126
126
  style,
127
127
  gl,
128
128
  events = createPointerEvents,
129
+ eventTarget,
130
+ eventPrefix,
129
131
  shadows,
130
132
  linear,
131
133
  flat,
@@ -184,7 +186,21 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(function Canvas({
184
186
  // Pass mutable reference to onPointerMissed so it's free to update
185
187
  onPointerMissed: (...args) => handlePointerMissed.current == null ? void 0 : handlePointerMissed.current(...args),
186
188
  onCreated: state => {
187
- state.events.connect == null ? void 0 : state.events.connect(divRef.current);
189
+ // Connect to event source
190
+ state.events.connect == null ? void 0 : state.events.connect(eventTarget ? eventTarget : divRef.current); // Set up compute function
191
+
192
+ if (eventPrefix) {
193
+ state.setEvents({
194
+ compute: (event, state) => {
195
+ const x = event[eventPrefix + 'X'];
196
+ const y = event[eventPrefix + 'Y'];
197
+ state.pointer.set(x / state.size.width * 2 - 1, -(y / state.size.height) * 2 + 1);
198
+ state.raycaster.setFromCamera(state.pointer, state.camera);
199
+ }
200
+ });
201
+ } // Call onCreated callback
202
+
203
+
188
204
  onCreated == null ? void 0 : onCreated(state);
189
205
  }
190
206
  });
@@ -1,5 +1,5 @@
1
- import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, E as ErrorBoundary, B as Block, b as useIsomorphicLayoutEffect, d as unmountComponentAtNode } from './index-201bf0bf.esm.js';
2
- export { t as ReactThreeFiber, s as _roots, q as act, n as addAfterEffect, m as addEffect, o as addTail, l as advance, i as applyProps, f as context, c as createEvents, g as createPortal, a as createRoot, j as dispose, e as extend, p as getRootState, k as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, x as useFrame, y as useGraph, z as useLoader, v as useStore, w as useThree } from './index-201bf0bf.esm.js';
1
+ import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, E as ErrorBoundary, B as Block, b as useIsomorphicLayoutEffect, d as unmountComponentAtNode } from './index-212b30d8.esm.js';
2
+ export { t as ReactThreeFiber, s as _roots, q as act, n as addAfterEffect, m as addEffect, o as addTail, l as advance, i as applyProps, f as context, c as createEvents, g as createPortal, a as createRoot, j as dispose, e as extend, p as getRootState, k as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, x as useFrame, y as useGraph, z as useLoader, v as useStore, w as useThree } from './index-212b30d8.esm.js';
3
3
  import _extends from '@babel/runtime/helpers/esm/extends';
4
4
  import * as React from 'react';
5
5
  import * as THREE from 'three';
@@ -99,6 +99,8 @@ const Canvas = /*#__PURE__*/React.forwardRef(function Canvas({
99
99
  style,
100
100
  gl,
101
101
  events = createPointerEvents,
102
+ eventTarget,
103
+ eventPrefix,
102
104
  shadows,
103
105
  linear,
104
106
  flat,
@@ -157,7 +159,21 @@ const Canvas = /*#__PURE__*/React.forwardRef(function Canvas({
157
159
  // Pass mutable reference to onPointerMissed so it's free to update
158
160
  onPointerMissed: (...args) => handlePointerMissed.current == null ? void 0 : handlePointerMissed.current(...args),
159
161
  onCreated: state => {
160
- state.events.connect == null ? void 0 : state.events.connect(divRef.current);
162
+ // Connect to event source
163
+ state.events.connect == null ? void 0 : state.events.connect(eventTarget ? eventTarget : divRef.current); // Set up compute function
164
+
165
+ if (eventPrefix) {
166
+ state.setEvents({
167
+ compute: (event, state) => {
168
+ const x = event[eventPrefix + 'X'];
169
+ const y = event[eventPrefix + 'Y'];
170
+ state.pointer.set(x / state.size.width * 2 - 1, -(y / state.size.height) * 2 + 1);
171
+ state.raycaster.setFromCamera(state.pointer, state.camera);
172
+ }
173
+ });
174
+ } // Call onCreated callback
175
+
176
+
161
177
  onCreated == null ? void 0 : onCreated(state);
162
178
  }
163
179
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('../../dist/index-942a305b.cjs.dev.js');
5
+ var index = require('../../dist/index-bcd3e47c.cjs.dev.js');
6
6
  var _extends = require('@babel/runtime/helpers/extends');
7
7
  var React = require('react');
8
8
  var THREE = require('three');
@@ -146,7 +146,7 @@ function getAsset(input) {
146
146
  return expAsset.fromModule(input);
147
147
 
148
148
  default:
149
- throw 'Invalid asset! Must be a URI or module.';
149
+ throw new Error('R3F: Invalid asset! Must be a URI or module.');
150
150
  }
151
151
  }
152
152
 
@@ -274,7 +274,7 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(({
274
274
  React__namespace.useImperativeHandle(forwardedRef, () => viewRef.current);
275
275
  const handlePointerMissed = index.useMutableCallback(onPointerMissed);
276
276
  const [block, setBlock] = React__namespace.useState(false);
277
- const [error, setError] = React__namespace.useState(false); // Suspend this component if block is a promise (2nd run)
277
+ const [error, setError] = React__namespace.useState(undefined); // Suspend this component if block is a promise (2nd run)
278
278
 
279
279
  if (block) throw block; // Throw exception outwards if anything within canvas throws
280
280
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('../../dist/index-1be7d4d7.cjs.prod.js');
5
+ var index = require('../../dist/index-e086bd20.cjs.prod.js');
6
6
  var _extends = require('@babel/runtime/helpers/extends');
7
7
  var React = require('react');
8
8
  var THREE = require('three');
@@ -146,7 +146,7 @@ function getAsset(input) {
146
146
  return expAsset.fromModule(input);
147
147
 
148
148
  default:
149
- throw 'Invalid asset! Must be a URI or module.';
149
+ throw new Error('R3F: Invalid asset! Must be a URI or module.');
150
150
  }
151
151
  }
152
152
 
@@ -274,7 +274,7 @@ const Canvas = /*#__PURE__*/React__namespace.forwardRef(({
274
274
  React__namespace.useImperativeHandle(forwardedRef, () => viewRef.current);
275
275
  const handlePointerMissed = index.useMutableCallback(onPointerMissed);
276
276
  const [block, setBlock] = React__namespace.useState(false);
277
- const [error, setError] = React__namespace.useState(false); // Suspend this component if block is a promise (2nd run)
277
+ const [error, setError] = React__namespace.useState(undefined); // Suspend this component if block is a promise (2nd run)
278
278
 
279
279
  if (block) throw block; // Throw exception outwards if anything within canvas throws
280
280
 
@@ -1,5 +1,5 @@
1
- import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, E as ErrorBoundary, B as Block, d as unmountComponentAtNode } from '../../dist/index-201bf0bf.esm.js';
2
- export { t as ReactThreeFiber, s as _roots, q as act, n as addAfterEffect, m as addEffect, o as addTail, l as advance, i as applyProps, f as context, g as createPortal, a as createRoot, j as dispose, e as extend, p as getRootState, k as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, x as useFrame, y as useGraph, z as useLoader, v as useStore, w as useThree } from '../../dist/index-201bf0bf.esm.js';
1
+ import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, E as ErrorBoundary, B as Block, d as unmountComponentAtNode } from '../../dist/index-212b30d8.esm.js';
2
+ export { t as ReactThreeFiber, s as _roots, q as act, n as addAfterEffect, m as addEffect, o as addTail, l as advance, i as applyProps, f as context, g as createPortal, a as createRoot, j as dispose, e as extend, p as getRootState, k as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, x as useFrame, y as useGraph, z as useLoader, v as useStore, w as useThree } from '../../dist/index-212b30d8.esm.js';
3
3
  import _extends from '@babel/runtime/helpers/esm/extends';
4
4
  import * as React from 'react';
5
5
  import * as THREE from 'three';
@@ -119,7 +119,7 @@ function getAsset(input) {
119
119
  return expAsset.fromModule(input);
120
120
 
121
121
  default:
122
- throw 'Invalid asset! Must be a URI or module.';
122
+ throw new Error('R3F: Invalid asset! Must be a URI or module.');
123
123
  }
124
124
  }
125
125
 
@@ -247,7 +247,7 @@ const Canvas = /*#__PURE__*/React.forwardRef(({
247
247
  React.useImperativeHandle(forwardedRef, () => viewRef.current);
248
248
  const handlePointerMissed = useMutableCallback(onPointerMissed);
249
249
  const [block, setBlock] = React.useState(false);
250
- const [error, setError] = React.useState(false); // Suspend this component if block is a promise (2nd run)
250
+ const [error, setError] = React.useState(undefined); // Suspend this component if block is a promise (2nd run)
251
251
 
252
252
  if (block) throw block; // Throw exception outwards if anything within canvas throws
253
253
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/fiber",
3
- "version": "8.2.3",
3
+ "version": "8.4.0",
4
4
  "description": "A React renderer for Threejs",
5
5
  "keywords": [
6
6
  "react",
package/readme.md CHANGED
@@ -164,7 +164,7 @@ Some reading material:
164
164
 
165
165
  - [Threejs-docs](https://threejs.org/docs)
166
166
  - [Threejs-examples](https://threejs.org/examples)
167
- - [Threejs-fundamentals](https://threejsfundamentals.org)
167
+ - [Threejs-fundamentals](https://threejs.org/manual/#en/fundamentals)
168
168
  - [Discover Threejs](https://discoverthreejs.com)
169
169
  - [Do's and don'ts](https://discoverthreejs.com/tips-and-tricks) for performance and best practices
170
170
  - [react-three-fiber alligator.io tutorial](https://alligator.io/react/react-with-threejs) by [@dghez\_](https://twitter.com/dghez_)