@react-three/fiber 8.8.9 → 8.8.11
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.
- package/CHANGELOG.md +12 -0
- package/dist/declarations/src/core/hooks.d.ts +8 -5
- package/dist/{index-409682b7.cjs.prod.js → index-4592040d.cjs.prod.js} +9 -4
- package/dist/{index-cd40f4c7.cjs.dev.js → index-b97b7ffd.cjs.dev.js} +9 -4
- package/dist/{index-8c780a08.esm.js → index-b9d9a4a8.esm.js} +9 -4
- package/dist/react-three-fiber.cjs.dev.js +1 -1
- package/dist/react-three-fiber.cjs.prod.js +1 -1
- package/dist/react-three-fiber.esm.js +2 -2
- package/native/dist/react-three-fiber-native.cjs.dev.js +1 -1
- package/native/dist/react-three-fiber-native.cjs.prod.js +1 -1
- package/native/dist/react-three-fiber-native.esm.js +2 -2
- package/package.json +2 -2
- package/readme.md +124 -73
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @react-three/fiber
|
|
2
2
|
|
|
3
|
+
## 8.8.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2068f0cc: fix: events pointerlock, useLoader extension types
|
|
8
|
+
|
|
9
|
+
## 8.8.10
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 00c24718: fix: invalidate pierced props
|
|
14
|
+
|
|
3
15
|
## 8.8.9
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -4,13 +4,16 @@ import { StateSelector, EqualityChecker } from 'zustand';
|
|
|
4
4
|
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
5
5
|
import { RootState, RenderCallback } from './store';
|
|
6
6
|
import { ObjectMap } from './utils';
|
|
7
|
-
import { LoadingManager } from 'three';
|
|
8
7
|
import { LocalState } from './renderer';
|
|
9
8
|
export interface Loader<T> extends THREE.Loader {
|
|
10
9
|
load(url: string, onLoad?: (result: T) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): unknown;
|
|
11
10
|
}
|
|
12
|
-
export declare type
|
|
11
|
+
export declare type LoaderProto<T> = new (...args: any) => Loader<T extends unknown ? any : T>;
|
|
12
|
+
export declare type LoaderReturnType<T, L extends LoaderProto<T>> = T extends unknown ? Awaited<ReturnType<InstanceType<L>['loadAsync']>> : T;
|
|
13
13
|
export declare type LoaderResult<T> = T extends any[] ? Loader<T[number]> : Loader<T>;
|
|
14
|
+
export declare type Extensions<T extends {
|
|
15
|
+
prototype: LoaderProto<any>;
|
|
16
|
+
}> = (loader: T['prototype']) => void;
|
|
14
17
|
export declare type ConditionalType<Child, Parent, Truthy, Falsy> = Child extends Parent ? Truthy : Falsy;
|
|
15
18
|
export declare type BranchingReturn<T, Parent, Coerced> = ConditionalType<T, Parent, Coerced, T>;
|
|
16
19
|
export declare function useInstanceHandle<O>(ref: React.MutableRefObject<O>): React.MutableRefObject<LocalState>;
|
|
@@ -18,8 +21,8 @@ export declare function useStore(): import("zustand").UseBoundStore<RootState, i
|
|
|
18
21
|
export declare function useThree<T = RootState>(selector?: StateSelector<RootState, T>, equalityFn?: EqualityChecker<T>): T;
|
|
19
22
|
export declare function useFrame(callback: RenderCallback, renderPriority?: number): null;
|
|
20
23
|
export declare function useGraph(object: THREE.Object3D): ObjectMap;
|
|
21
|
-
export declare function useLoader<T, U extends string | string[]
|
|
24
|
+
export declare function useLoader<T, U extends string | string[], L extends LoaderProto<T>, R = LoaderReturnType<T, L>>(Proto: L, input: U, extensions?: Extensions<L>, onProgress?: (event: ProgressEvent<EventTarget>) => void): U extends any[] ? BranchingReturn<R, GLTF, GLTF & ObjectMap>[] : BranchingReturn<R, GLTF, GLTF & ObjectMap>;
|
|
22
25
|
export declare namespace useLoader {
|
|
23
|
-
var preload: <T, U extends string | string[]
|
|
24
|
-
var clear: <T, U extends string | string[]
|
|
26
|
+
var preload: <T, U extends string | string[], L extends LoaderProto<T>>(Proto: L, input: U, extensions?: Extensions<L> | undefined) => undefined;
|
|
27
|
+
var clear: <T, U extends string | string[], L extends LoaderProto<T>>(Proto: L, input: U) => void;
|
|
25
28
|
}
|
|
@@ -283,7 +283,12 @@ function diffProps(instance, {
|
|
|
283
283
|
|
|
284
284
|
let entries = [];
|
|
285
285
|
if (key.includes('-')) entries = key.split('-');
|
|
286
|
-
changes.push([key, value, false, entries]);
|
|
286
|
+
changes.push([key, value, false, entries]); // Reset pierced props
|
|
287
|
+
|
|
288
|
+
for (const prop in props) {
|
|
289
|
+
const value = props[prop];
|
|
290
|
+
if (prop.startsWith(`${key}-`)) changes.push([prop, value, false, prop.split('-')]);
|
|
291
|
+
}
|
|
287
292
|
});
|
|
288
293
|
const memoized = { ...props
|
|
289
294
|
};
|
|
@@ -574,7 +579,7 @@ function createEvents(store) {
|
|
|
574
579
|
.sort((a, b) => {
|
|
575
580
|
const aState = getRootState(a.object);
|
|
576
581
|
const bState = getRootState(b.object);
|
|
577
|
-
if (!aState || !bState) return
|
|
582
|
+
if (!aState || !bState) return a.distance - b.distance;
|
|
578
583
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
579
584
|
}) // Filter out duplicates
|
|
580
585
|
.filter(item => {
|
|
@@ -603,7 +608,7 @@ function createEvents(store) {
|
|
|
603
608
|
|
|
604
609
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
605
610
|
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
606
|
-
intersections.push(captureData.intersection);
|
|
611
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
607
612
|
}
|
|
608
613
|
}
|
|
609
614
|
|
|
@@ -772,7 +777,7 @@ function createEvents(store) {
|
|
|
772
777
|
internal
|
|
773
778
|
} = store.getState();
|
|
774
779
|
|
|
775
|
-
if ('pointerId' in event &&
|
|
780
|
+
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
776
781
|
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
777
782
|
// object that's getting removed.
|
|
778
783
|
internal.capturedMap.delete(event.pointerId);
|
|
@@ -283,7 +283,12 @@ function diffProps(instance, {
|
|
|
283
283
|
|
|
284
284
|
let entries = [];
|
|
285
285
|
if (key.includes('-')) entries = key.split('-');
|
|
286
|
-
changes.push([key, value, false, entries]);
|
|
286
|
+
changes.push([key, value, false, entries]); // Reset pierced props
|
|
287
|
+
|
|
288
|
+
for (const prop in props) {
|
|
289
|
+
const value = props[prop];
|
|
290
|
+
if (prop.startsWith(`${key}-`)) changes.push([prop, value, false, prop.split('-')]);
|
|
291
|
+
}
|
|
287
292
|
});
|
|
288
293
|
const memoized = { ...props
|
|
289
294
|
};
|
|
@@ -574,7 +579,7 @@ function createEvents(store) {
|
|
|
574
579
|
.sort((a, b) => {
|
|
575
580
|
const aState = getRootState(a.object);
|
|
576
581
|
const bState = getRootState(b.object);
|
|
577
|
-
if (!aState || !bState) return
|
|
582
|
+
if (!aState || !bState) return a.distance - b.distance;
|
|
578
583
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
579
584
|
}) // Filter out duplicates
|
|
580
585
|
.filter(item => {
|
|
@@ -603,7 +608,7 @@ function createEvents(store) {
|
|
|
603
608
|
|
|
604
609
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
605
610
|
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
606
|
-
intersections.push(captureData.intersection);
|
|
611
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
607
612
|
}
|
|
608
613
|
}
|
|
609
614
|
|
|
@@ -772,7 +777,7 @@ function createEvents(store) {
|
|
|
772
777
|
internal
|
|
773
778
|
} = store.getState();
|
|
774
779
|
|
|
775
|
-
if ('pointerId' in event &&
|
|
780
|
+
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
776
781
|
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
777
782
|
// object that's getting removed.
|
|
778
783
|
internal.capturedMap.delete(event.pointerId);
|
|
@@ -256,7 +256,12 @@ function diffProps(instance, {
|
|
|
256
256
|
|
|
257
257
|
let entries = [];
|
|
258
258
|
if (key.includes('-')) entries = key.split('-');
|
|
259
|
-
changes.push([key, value, false, entries]);
|
|
259
|
+
changes.push([key, value, false, entries]); // Reset pierced props
|
|
260
|
+
|
|
261
|
+
for (const prop in props) {
|
|
262
|
+
const value = props[prop];
|
|
263
|
+
if (prop.startsWith(`${key}-`)) changes.push([prop, value, false, prop.split('-')]);
|
|
264
|
+
}
|
|
260
265
|
});
|
|
261
266
|
const memoized = { ...props
|
|
262
267
|
};
|
|
@@ -547,7 +552,7 @@ function createEvents(store) {
|
|
|
547
552
|
.sort((a, b) => {
|
|
548
553
|
const aState = getRootState(a.object);
|
|
549
554
|
const bState = getRootState(b.object);
|
|
550
|
-
if (!aState || !bState) return
|
|
555
|
+
if (!aState || !bState) return a.distance - b.distance;
|
|
551
556
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
552
557
|
}) // Filter out duplicates
|
|
553
558
|
.filter(item => {
|
|
@@ -576,7 +581,7 @@ function createEvents(store) {
|
|
|
576
581
|
|
|
577
582
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
578
583
|
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
579
|
-
intersections.push(captureData.intersection);
|
|
584
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
580
585
|
}
|
|
581
586
|
}
|
|
582
587
|
|
|
@@ -745,7 +750,7 @@ function createEvents(store) {
|
|
|
745
750
|
internal
|
|
746
751
|
} = store.getState();
|
|
747
752
|
|
|
748
|
-
if ('pointerId' in event &&
|
|
753
|
+
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
749
754
|
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
750
755
|
// object that's getting removed.
|
|
751
756
|
internal.capturedMap.delete(event.pointerId);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var index = require('./index-
|
|
5
|
+
var index = require('./index-b97b7ffd.cjs.dev.js');
|
|
6
6
|
var _extends = require('@babel/runtime/helpers/extends');
|
|
7
7
|
var React = require('react');
|
|
8
8
|
var THREE = require('three');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var index = require('./index-
|
|
5
|
+
var index = require('./index-4592040d.cjs.prod.js');
|
|
6
6
|
var _extends = require('@babel/runtime/helpers/extends');
|
|
7
7
|
var React = require('react');
|
|
8
8
|
var THREE = require('three');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, i as isRef, E as ErrorBoundary, B as Block, b as useIsomorphicLayoutEffect, d as unmountComponentAtNode } from './index-
|
|
2
|
-
export { t as ReactThreeFiber, v as _roots, s as act, o as addAfterEffect, n as addEffect, p as addTail, m as advance, j as applyProps, f as context, c as createEvents, g as createPortal, a as createRoot, k as dispose, e as extend, q as getRootState, l as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, z as useFrame, A as useGraph, w as useInstanceHandle, C as useLoader, x as useStore, y as useThree } from './index-
|
|
1
|
+
import { c as createEvents, e as extend, u as useMutableCallback, a as createRoot, i as isRef, E as ErrorBoundary, B as Block, b as useIsomorphicLayoutEffect, d as unmountComponentAtNode } from './index-b9d9a4a8.esm.js';
|
|
2
|
+
export { t as ReactThreeFiber, v as _roots, s as act, o as addAfterEffect, n as addEffect, p as addTail, m as advance, j as applyProps, f as context, c as createEvents, g as createPortal, a as createRoot, k as dispose, e as extend, q as getRootState, l as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, z as useFrame, A as useGraph, w as useInstanceHandle, C as useLoader, x as useStore, y as useThree } from './index-b9d9a4a8.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';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var index = require('../../dist/index-
|
|
5
|
+
var index = require('../../dist/index-b97b7ffd.cjs.dev.js');
|
|
6
6
|
var _extends = require('@babel/runtime/helpers/extends');
|
|
7
7
|
var React = require('react');
|
|
8
8
|
var THREE = require('three');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var index = require('../../dist/index-
|
|
5
|
+
var index = require('../../dist/index-4592040d.cjs.prod.js');
|
|
6
6
|
var _extends = require('@babel/runtime/helpers/extends');
|
|
7
7
|
var React = require('react');
|
|
8
8
|
var THREE = require('three');
|
|
@@ -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-
|
|
2
|
-
export { t as ReactThreeFiber, v as _roots, s as act, o as addAfterEffect, n as addEffect, p as addTail, m as advance, j as applyProps, f as context, g as createPortal, a as createRoot, k as dispose, e as extend, q as getRootState, l as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, z as useFrame, A as useGraph, w as useInstanceHandle, C as useLoader, x as useStore, y as useThree } from '../../dist/index-
|
|
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-b9d9a4a8.esm.js';
|
|
2
|
+
export { t as ReactThreeFiber, v as _roots, s as act, o as addAfterEffect, n as addEffect, p as addTail, m as advance, j as applyProps, f as context, g as createPortal, a as createRoot, k as dispose, e as extend, q as getRootState, l as invalidate, h as reconciler, r as render, d as unmountComponentAtNode, z as useFrame, A as useGraph, w as useInstanceHandle, C as useLoader, x as useStore, y as useThree } from '../../dist/index-b9d9a4a8.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';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-three/fiber",
|
|
3
|
-
"version": "8.8.
|
|
3
|
+
"version": "8.8.11",
|
|
4
4
|
"description": "A React renderer for Threejs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@babel/runtime": "^7.17.8",
|
|
46
46
|
"@types/react-reconciler": "^0.26.7",
|
|
47
|
-
"its-fine": "^1.0.
|
|
47
|
+
"its-fine": "^1.0.6",
|
|
48
48
|
"react-reconciler": "^0.27.0",
|
|
49
49
|
"react-use-measure": "^2.1.1",
|
|
50
50
|
"scheduler": "^0.21.0",
|
package/readme.md
CHANGED
|
@@ -10,112 +10,160 @@
|
|
|
10
10
|
|
|
11
11
|
react-three-fiber is a <a href="https://reactjs.org/docs/codebase-overview.html#renderers">React renderer</a> for threejs.
|
|
12
12
|
|
|
13
|
+
Build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can participate in React's ecosystem.
|
|
14
|
+
|
|
13
15
|
```bash
|
|
14
16
|
npm install three @react-three/fiber
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
### Why?
|
|
18
|
-
|
|
19
|
-
Build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can tap into React's ecosystem.
|
|
20
|
-
|
|
21
19
|
#### Does it have limitations?
|
|
22
20
|
|
|
23
|
-
None. Everything that works in
|
|
21
|
+
None. Everything that works in Threejs will work here without exception.
|
|
24
22
|
|
|
25
|
-
####
|
|
23
|
+
#### Is it slower than plain Threejs?
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
No. There is no overhead. Components render outside of React. It outperforms Threejs in scale due to Reacts scheduling abilities.
|
|
28
26
|
|
|
29
|
-
####
|
|
27
|
+
#### Can it keep up with frequent feature updates to Threejs?
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
Yes. It merely expresses Threejs in JSX: `<mesh />` becomes `new THREE.Mesh()`, and that happens dynamically. If a new Threejs version adds, removes or changes features, it will be available to you instantly without depending on updates to this library.
|
|
32
30
|
|
|
33
31
|
### What does it look like?
|
|
34
32
|
|
|
35
33
|
<table>
|
|
36
|
-
<
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
<tbody>
|
|
35
|
+
<tr>
|
|
36
|
+
<td>Let's make a re-usable component that has its own state, reacts to user-input and participates in the render-loop. (<a href="https://codesandbox.io/s/rrppl0y8l4?file=/src/App.js">live demo</a>).</td>
|
|
37
|
+
<td>
|
|
38
|
+
<a href="https://codesandbox.io/s/rrppl0y8l4">
|
|
39
|
+
<img src="https://i.imgur.com/sS4ArrZ.gif" />
|
|
40
|
+
</a>
|
|
41
|
+
</td>
|
|
42
|
+
</tr>
|
|
43
|
+
</tbody>
|
|
43
44
|
</table>
|
|
44
45
|
|
|
45
|
-
#### Imports first
|
|
46
|
-
|
|
47
46
|
```jsx
|
|
47
|
+
import { createRoot } from 'react-dom/client'
|
|
48
48
|
import React, { useRef, useState } from 'react'
|
|
49
|
-
import ReactDOM from 'react-dom'
|
|
50
49
|
import { Canvas, useFrame } from '@react-three/fiber'
|
|
51
|
-
```
|
|
52
50
|
|
|
53
|
-
#### Define a component
|
|
54
|
-
|
|
55
|
-
```jsx
|
|
56
51
|
function Box(props) {
|
|
57
|
-
// This reference
|
|
58
|
-
const
|
|
59
|
-
//
|
|
60
|
-
const [hovered,
|
|
61
|
-
const [
|
|
62
|
-
//
|
|
63
|
-
useFrame(() => (
|
|
64
|
-
|
|
52
|
+
// This reference gives us direct access to the THREE.Mesh object
|
|
53
|
+
const ref = useRef()
|
|
54
|
+
// Hold state for hovered and clicked events
|
|
55
|
+
const [hovered, hover] = useState(false)
|
|
56
|
+
const [clicked, click] = useState(false)
|
|
57
|
+
// Subscribe this component to the render-loop, rotate the mesh every frame
|
|
58
|
+
useFrame((state, delta) => (ref.current.rotation.x += 0.01))
|
|
59
|
+
// Return the view, these are regular Threejs elements expressed in JSX
|
|
65
60
|
return (
|
|
66
61
|
<mesh
|
|
67
62
|
{...props}
|
|
68
|
-
ref={
|
|
69
|
-
scale={
|
|
70
|
-
onClick={(event) =>
|
|
71
|
-
onPointerOver={(event) =>
|
|
72
|
-
onPointerOut={(event) =>
|
|
73
|
-
<boxGeometry args={[1,
|
|
63
|
+
ref={ref}
|
|
64
|
+
scale={clicked ? 1.5 : 1}
|
|
65
|
+
onClick={(event) => click(!clicked)}
|
|
66
|
+
onPointerOver={(event) => hover(true)}
|
|
67
|
+
onPointerOut={(event) => hover(false)}>
|
|
68
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
74
69
|
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
|
|
75
70
|
</mesh>
|
|
76
71
|
)
|
|
77
72
|
}
|
|
73
|
+
|
|
74
|
+
createRoot(document.getElementById('root')).render(
|
|
75
|
+
<Canvas>
|
|
76
|
+
<ambientLight />
|
|
77
|
+
<pointLight position={[10, 10, 10]} />
|
|
78
|
+
<Box position={[-1.2, 0, 0]} />
|
|
79
|
+
<Box position={[1.2, 0, 0]} />
|
|
80
|
+
</Canvas>,
|
|
81
|
+
)
|
|
78
82
|
```
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
<details>
|
|
85
|
+
<summary>Show TypeScript example</summary>
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm install @types/three
|
|
89
|
+
```
|
|
81
90
|
|
|
82
|
-
|
|
91
|
+
```tsx
|
|
92
|
+
import * as THREE from 'three'
|
|
93
|
+
import { createRoot } from 'react-dom/client'
|
|
94
|
+
import React, { useRef, useState } from 'react'
|
|
95
|
+
import { Canvas, useFrame, ThreeElements } from '@react-three/fiber'
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
function Box(props: ThreeElements['mesh']) {
|
|
98
|
+
const ref = useRef<THREE.Mesh>(null!)
|
|
99
|
+
const [hovered, hover] = useState(false)
|
|
100
|
+
const [clicked, click] = useState(false)
|
|
101
|
+
useFrame((state, delta) => (ref.current.rotation.x += 0.01))
|
|
102
|
+
return (
|
|
103
|
+
<mesh
|
|
104
|
+
{...props}
|
|
105
|
+
ref={ref}
|
|
106
|
+
scale={clicked ? 1.5 : 1}
|
|
107
|
+
onClick={(event) => click(!clicked)}
|
|
108
|
+
onPointerOver={(event) => hover(true)}
|
|
109
|
+
onPointerOut={(event) => hover(false)}>
|
|
110
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
111
|
+
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
|
|
112
|
+
</mesh>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
createRoot(document.getElementById('root') as HTMLElement).render(
|
|
86
117
|
<Canvas>
|
|
87
118
|
<ambientLight />
|
|
88
119
|
<pointLight position={[10, 10, 10]} />
|
|
89
120
|
<Box position={[-1.2, 0, 0]} />
|
|
90
121
|
<Box position={[1.2, 0, 0]} />
|
|
91
122
|
</Canvas>,
|
|
92
|
-
document.getElementById('root'),
|
|
93
123
|
)
|
|
94
124
|
```
|
|
95
125
|
|
|
96
|
-
|
|
126
|
+
Live demo: https://codesandbox.io/s/icy-tree-brnsm?file=/src/App.tsx
|
|
97
127
|
|
|
98
|
-
|
|
99
|
-
|
|
128
|
+
</details>
|
|
129
|
+
|
|
130
|
+
<details>
|
|
131
|
+
<summary>Show React Native example</summary>
|
|
132
|
+
|
|
133
|
+
This example relies on react 18 and uses `expo-cli`, but you can create a bare project with their template or with the `react-native` CLI.
|
|
100
134
|
|
|
101
|
-
|
|
135
|
+
```bash
|
|
136
|
+
# Install expo-cli, this will create our app
|
|
137
|
+
npm install expo-cli -g
|
|
138
|
+
# Create app and cd into it
|
|
139
|
+
expo init my-app
|
|
140
|
+
cd my-app
|
|
141
|
+
# Install dependencies
|
|
142
|
+
npm install three @react-three/fiber@beta react@rc
|
|
143
|
+
# Start
|
|
144
|
+
expo start
|
|
102
145
|
```
|
|
103
146
|
|
|
104
|
-
|
|
105
|
-
<summary>Show TypeScript example</summary>
|
|
147
|
+
Some configuration may be required to tell the Metro bundler about your assets if you use `useLoader` or Drei abstractions like `useGLTF` and `useTexture`:
|
|
106
148
|
|
|
107
|
-
```
|
|
108
|
-
|
|
149
|
+
```js
|
|
150
|
+
// metro.config.js
|
|
151
|
+
module.exports = {
|
|
152
|
+
resolver: {
|
|
153
|
+
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'cjs'],
|
|
154
|
+
assetExts: ['glb', 'png', 'jpg'],
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
```
|
|
109
158
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
159
|
+
```tsx
|
|
160
|
+
import React, { useRef, useState } from 'react'
|
|
161
|
+
import { Canvas, useFrame } from '@react-three/fiber/native'
|
|
162
|
+
function Box(props) {
|
|
163
|
+
const mesh = useRef(null)
|
|
114
164
|
const [hovered, setHover] = useState(false)
|
|
115
165
|
const [active, setActive] = useState(false)
|
|
116
|
-
|
|
117
|
-
useFrame(() => (mesh.current.rotation.x += 0.01))
|
|
118
|
-
|
|
166
|
+
useFrame((state, delta) => (mesh.current.rotation.x += 0.01))
|
|
119
167
|
return (
|
|
120
168
|
<mesh
|
|
121
169
|
{...props}
|
|
@@ -124,32 +172,32 @@ const Box: React.FC<MeshProps> = (props) => {
|
|
|
124
172
|
onClick={(event) => setActive(!active)}
|
|
125
173
|
onPointerOver={(event) => setHover(true)}
|
|
126
174
|
onPointerOut={(event) => setHover(false)}>
|
|
127
|
-
<boxGeometry args={[1,
|
|
175
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
128
176
|
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
|
|
129
177
|
</mesh>
|
|
130
178
|
)
|
|
131
179
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
180
|
+
export default function App() {
|
|
181
|
+
return (
|
|
182
|
+
<Canvas>
|
|
183
|
+
<ambientLight />
|
|
184
|
+
<pointLight position={[10, 10, 10]} />
|
|
185
|
+
<Box position={[-1.2, 0, 0]} />
|
|
186
|
+
<Box position={[1.2, 0, 0]} />
|
|
187
|
+
</Canvas>
|
|
188
|
+
)
|
|
189
|
+
}
|
|
142
190
|
```
|
|
143
191
|
|
|
144
192
|
</details>
|
|
145
193
|
|
|
146
194
|
---
|
|
147
195
|
|
|
148
|
-
# Documentation
|
|
196
|
+
# Documentation, tutorials, examples
|
|
197
|
+
|
|
198
|
+
Visit [docs.pmnd.rs](https://docs.pmnd.rs/react-three-fiber)
|
|
149
199
|
|
|
150
|
-
|
|
151
|
-
- [pitfalls.md](/markdown/pitfalls.md)
|
|
152
|
-
- [testing.md](/packages/test-renderer)
|
|
200
|
+
<a href="https://docs.pmnd.rs/react-three-fiber"><img src="/docs/preview.jpg"></a>
|
|
153
201
|
|
|
154
202
|
# Fundamentals
|
|
155
203
|
|
|
@@ -158,13 +206,14 @@ You need to be versed in both React and Threejs before rushing into this. If you
|
|
|
158
206
|
1. Make sure you have a [basic grasp of Threejs](https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene). Keep that site open.
|
|
159
207
|
2. When you know what a scene is, a camera, mesh, geometry, material, fork the [demo above](https://github.com/pmndrs/react-three-fiber#what-does-it-look-like).
|
|
160
208
|
3. [Look up](https://threejs.org/docs/index.html#api/en/objects/Mesh) the JSX elements that you see (mesh, ambientLight, etc), _all_ threejs exports are native to three-fiber.
|
|
161
|
-
4. Try changing some values, scroll
|
|
209
|
+
4. Try changing some values, scroll through our [API](https://docs.pmnd.rs/react-three-fiber/API) to see what the various settings and hooks do.
|
|
162
210
|
|
|
163
211
|
Some reading material:
|
|
164
212
|
|
|
165
213
|
- [Threejs-docs](https://threejs.org/docs)
|
|
166
214
|
- [Threejs-examples](https://threejs.org/examples)
|
|
167
215
|
- [Threejs-fundamentals](https://threejs.org/manual/#en/fundamentals)
|
|
216
|
+
- [three.js-journey](https://threejs-journey.com)
|
|
168
217
|
- [Discover Threejs](https://discoverthreejs.com)
|
|
169
218
|
- [Do's and don'ts](https://discoverthreejs.com/tips-and-tricks) for performance and best practices
|
|
170
219
|
- [react-three-fiber alligator.io tutorial](https://alligator.io/react/react-with-threejs) by [@dghez\_](https://twitter.com/dghez_)
|
|
@@ -177,9 +226,11 @@ Some reading material:
|
|
|
177
226
|
- [`@react-three/flex`](https://github.com/pmndrs/react-three-flex) – flexbox for react-three-fiber
|
|
178
227
|
- [`@react-three/xr`](https://github.com/pmndrs/react-xr) – VR/AR controllers and events
|
|
179
228
|
- [`@react-three/cannon`](https://github.com/pmndrs/use-cannon) – physics based hooks
|
|
229
|
+
- [`@react-three/a11y`](https://github.com/pmndrs/react-three-a11y) – real a11y for your scene
|
|
180
230
|
- [`zustand`](https://github.com/pmndrs/zustand) – state management
|
|
181
231
|
- [`react-spring`](https://github.com/pmndrs/react-spring) – a spring-physics-based animation library
|
|
182
232
|
- [`react-use-gesture`](https://github.com/pmndrs/react-use-gesture) – mouse/touch gestures
|
|
233
|
+
- [`leva`](https://github.com/pmndrs/leva) – create GUI controls in seconds
|
|
183
234
|
|
|
184
235
|
# How to contribute
|
|
185
236
|
|