Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pmndrs/react-three-fiber
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d8bce4826f171463dae2cc814b7b32e057e0327c
Choose a base ref
...
head repository: pmndrs/react-three-fiber
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3da2dce382c355d71392899de0afe6fe6f489198
Choose a head ref
Loading
Showing with 7,320 additions and 4,701 deletions.
  1. +4 −1 .changeset/config.json
  2. +10 −3 .eslintrc.json
  3. +8 −5 .github/workflows/test.yml
  4. +79 −0 CONTRIBUTING.md
  5. +1 −0 babel.config.js
  6. +16 −14 docs/API/additional-exports.mdx
  7. +42 −40 docs/API/canvas.mdx
  8. +94 −0 docs/API/events.mdx
  9. +35 −27 docs/API/hooks.mdx
  10. +56 −27 docs/API/objects.mdx
  11. +0 −45 docs/advanced/gotchas.mdx
  12. +72 −47 docs/advanced/pitfalls.mdx
  13. +69 −11 docs/advanced/scaling-performance.mdx
  14. BIN docs/banner-journey.jpg
  15. BIN docs/banner-r3f.jpg
  16. BIN docs/basic-app.gif
  17. BIN docs/getting-started/basic-example.gif
  18. +210 −126 docs/getting-started/examples.mdx
  19. +57 −27 docs/getting-started/installation.mdx
  20. +85 −56 docs/getting-started/introduction.mdx
  21. +2 −2 docs/getting-started/your-first-scene.mdx
  22. +1 −1 docs/tutorials/basic-animations.mdx
  23. +2 −2 docs/tutorials/events-and-interaction.mdx
  24. BIN docs/tutorials/gltfjsx.png
  25. +9 −9 docs/tutorials/how-it-works.mdx
  26. +6 −10 docs/tutorials/loading-models.mdx
  27. +1 −1 docs/tutorials/loading-textures.mdx
  28. +1 −1 docs/tutorials/testing.mdx
  29. +11 −13 docs/tutorials/typescript.mdx
  30. +14 −14 docs/tutorials/using-with-react-spring.mdx
  31. +8 −8 docs/tutorials/v8-migration-guide.mdx
  32. +6 −0 example/CHANGELOG.md
  33. +17 −16 example/package.json
  34. +1 −0 example/public/apple.gltf
  35. +1 −0 example/public/bottle.gltf
  36. +1 −0 example/public/farm.gltf
  37. +123 −0 example/public/lightning.gltf
  38. +1 −0 example/public/ramen.gltf
  39. +1 −1 example/src/demos/Animation.tsx
  40. +2 −2 example/src/demos/AutoDispose.tsx
  41. +1 −1 example/src/demos/ClickAndHover.tsx
  42. +2 −1 example/src/demos/ContextMenuOverride.tsx
  43. +10 −1 example/src/demos/Gestures.tsx
  44. +1 −2 example/src/demos/Gltf.tsx
  45. +29 −46 example/src/demos/Lines.tsx
  46. +5 −2 example/src/demos/MultiMaterial.tsx
  47. +1 −1 example/src/demos/MultiRender.tsx
  48. +2 −4 example/src/demos/MultiView.tsx
  49. +5 −11 example/src/demos/Pointcloud.tsx
  50. +14 −11 example/src/demos/Portals.tsx
  51. +3 −3 example/src/demos/ResetProps.tsx
  52. +1 −1 example/src/demos/Selection.tsx
  53. +1 −3 example/src/demos/StopPropagation.tsx
  54. +1 −1 example/src/demos/SuspenseMaterial.tsx
  55. +6 −2 example/src/demos/Test.tsx
  56. +14 −25 example/src/demos/ViewTracking.tsx
  57. +1 −2 example/src/index.tsx
  58. +1 −2 example/tsconfig.json
  59. +11 −0 example/typings/global.d.ts
  60. +2 −2 example/vite.config.ts
  61. +1 −9 jest.config.js
  62. +13 −10 package.json
  63. +3 −0 packages/eslint-plugin/.npmignore
  64. +7 −0 packages/eslint-plugin/CHANGELOG.md
  65. +82 −0 packages/eslint-plugin/README.md
  66. +52 −0 packages/eslint-plugin/docs/rules/no-clone-in-loop.md
  67. +52 −0 packages/eslint-plugin/docs/rules/no-new-in-loop.md
  68. +50 −0 packages/eslint-plugin/package.json
  69. +155 −0 packages/eslint-plugin/scripts/codegen.ts
  70. +10 −0 packages/eslint-plugin/src/configs/all.ts
  71. +10 −0 packages/eslint-plugin/src/configs/recommended.ts
  72. +12 −0 packages/eslint-plugin/src/index.ts
  73. +3 −0 packages/eslint-plugin/src/lib/url.ts
  74. +10 −0 packages/eslint-plugin/src/rules/index.ts
  75. +31 −0 packages/eslint-plugin/src/rules/no-clone-in-loop.ts
  76. +29 −0 packages/eslint-plugin/src/rules/no-new-in-loop.ts
  77. +38 −0 packages/eslint-plugin/tests/rules/no-clone-in-loop.test.ts
  78. +57 −0 packages/eslint-plugin/tests/rules/no-new-in-loop.test.ts
  79. +511 −0 packages/fiber/CHANGELOG.md
  80. +3 −3 packages/fiber/__mocks__/expo-asset.ts
  81. +2 −2 packages/fiber/__mocks__/expo-gl.ts
  82. +16 −2 packages/fiber/__mocks__/{react-native/index.ts → react-native.ts}
  83. +0 −2 packages/fiber/__mocks__/react-native/Libraries/Pressability/Pressability.ts
  84. +9 −4 packages/fiber/package.json
  85. +126 −75 packages/fiber/readme.md
  86. +89 −53 packages/fiber/src/core/events.ts
  87. +50 −21 packages/fiber/src/core/hooks.tsx
  88. +175 −99 packages/fiber/src/core/index.tsx
  89. +38 −21 packages/fiber/src/core/loop.ts
  90. +133 −79 packages/fiber/src/core/renderer.ts
  91. +87 −45 packages/fiber/src/core/store.ts
  92. +131 −75 packages/fiber/src/core/utils.ts
  93. +2 −0 packages/fiber/src/index.tsx
  94. +5 −120 packages/fiber/src/native.tsx
  95. +89 −63 packages/fiber/src/native/Canvas.tsx
  96. +33 −45 packages/fiber/src/native/events.ts
  97. +230 −0 packages/fiber/src/native/polyfills.ts
  98. +185 −168 packages/fiber/src/three-types.ts
  99. +125 −69 packages/fiber/src/web/Canvas.tsx
  100. +5 −1 packages/fiber/src/web/events.ts
  101. +114 −89 packages/fiber/tests/core/events.test.tsx
  102. +72 −50 packages/fiber/tests/core/hooks.test.tsx
  103. +416 −126 packages/fiber/tests/core/renderer.test.tsx
  104. +7 −0 packages/fiber/tests/core/utils.test.ts
  105. +1 −1 packages/fiber/tests/native/canvas.test.tsx
  106. +13 −28 packages/fiber/tests/native/hooks.test.tsx
  107. +6 −5 packages/fiber/tests/setupTests.ts
  108. +11 −7 packages/fiber/tests/web/__snapshots__/canvas.test.tsx.snap
  109. +0 −97 packages/shared/asyncUtils.ts
  110. +4 −1 packages/shared/setupTests.ts
  111. +120 −0 packages/test-renderer/CHANGELOG.md
  112. +1 −1 packages/test-renderer/README.md
  113. +1 −1 packages/test-renderer/markdown/rttr.md
  114. +2 −2 packages/test-renderer/package.json
  115. +272 −33 packages/test-renderer/src/{createWebGLContext.ts → WebGL2RenderingContext.ts}
  116. +24 −7 packages/test-renderer/src/__tests__/RTTR.core.test.tsx
  117. +10 −16 packages/test-renderer/src/__tests__/RTTR.hooks.test.tsx
  118. +2 −2 packages/test-renderer/src/__tests__/RTTR.methods.test.tsx
  119. +7 −7 packages/test-renderer/src/__tests__/__snapshots__/RTTR.core.test.tsx.snap
  120. +30 −7 packages/test-renderer/src/createTestCanvas.ts
  121. +24 −0 packages/test-renderer/src/helpers/waitFor.ts
  122. +31 −63 packages/test-renderer/src/index.tsx
  123. +2 −2 packages/test-renderer/src/types/internal.ts
  124. +54 −34 readme.md
  125. +4 −2 tsconfig.json
  126. +2,276 −2,524 yarn.lock
5 changes: 4 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
@@ -6,5 +6,8 @@
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "minor",
"ignore": []
"ignore": [],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}
13 changes: 10 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -4,8 +4,14 @@
"es6": true,
"node": true
},
"extends": ["prettier", "plugin:prettier/recommended", "plugin:react-hooks/recommended", "plugin:import/recommended"],
"plugins": ["@typescript-eslint", "react", "react-hooks", "import", "jest", "prettier"],
"extends": [
"prettier",
"plugin:prettier/recommended",
"plugin:react-hooks/recommended",
"plugin:import/recommended",
"plugin:@react-three/recommended"
],
"plugins": ["@typescript-eslint", "react", "react-hooks", "import", "jest", "prettier", "@react-three"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
@@ -64,6 +70,7 @@
"rules": {
"import/no-unresolved": "off",
"import/named": "off",
"import/namespace": "off"
"import/namespace": "off",
"import/no-named-as-default-member": "off"
}
}
13 changes: 8 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -24,16 +24,19 @@ jobs:
install-command: yarn --immutable --silent

- name: Check types
run: yarn typecheck
run: yarn run typecheck

- name: Check lint
run: yarn run eslint

- name: Build
run: yarn build
run: yarn run build

- name: Jest run
run: yarn test
run: yarn run test

- name: Report Fiber size
run: yarn analyze-fiber
run: yarn run analyze-fiber

- name: Report Test Renderer size
run: yarn analyze-test
run: yarn run analyze-test
79 changes: 79 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## Contributing

This project uses [semantic commits](https://conventionalcommits.org) and [semver](https://semver.org).

To get started, make sure you have [Node](https://nodejs.org) and [Yarn 1](https://classic.yarnpkg.com) (newer versions of Yarn do not work) installed. Install dependencies with:

```bash
yarn
```

[Preconstruct](https://github.com/preconstruct/preconstruct) will automatically build and link packages for local development via symlinks. If you ever need to do this manually, try running:

```bash
yarn dev
```

> **Note**: Some Windows users may need to [enable developer mode](https://howtogeek.com/292914/what-is-developer-mode-in-windows-10) if experiencing `EPERM: operation not permitted, symlink` with Preconstruct. If this persists, you might be running on an unsupported drive/format. In which case, consider using [Docker](https://docs.docker.com/docker-for-windows).
### Development

Locally run examples against the library with:

```bash
yarn examples
```

### Testing

Run test suites against the library with:

```bash
yarn test

# or, to test live against changes
yarn test:watch
```

If your code invalidates a snapshot, you can update it with:

```bash
yarn test -u
```

> **Note**: Use discretion when updating snapshots, as they represent the integrity of the package.
>
> If the difference is complex or you're unsure of the changes, leave it for review and we'll unblock it.
### Publishing

We use [atlassian/changesets](https://github.com/atlassian/changesets) to publish our packages, which will automatically document and version changes.

To publish a release on NPM, run the following and complete the dialog (see [FAQ](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)):

```bash
# Describe the changes you've made as you would semantic commits for CHANGELOG.md
yarn changeset:add

# Tag which packages should receive an update and be published.
yarn vers

# Commit and publish changes to NPM.
yarn release
```

We don't have automatic CI deployments yet, so make sure to [create a release](https://github.com/pmndrs/react-three-fiber/releases/new) on GitHub to notify people when it's ready. Choose or create the version generated by your changeset, and you can leave the rest to auto-fill via the "Generate release notes" button to describe PRs since the last release.

### Prerelease

Follow the same steps as before, but specify a tag for [prerelease mode](https://github.com/changesets/changesets/blob/main/docs/prereleases.md) with:

```bash
yarn changeset pre enter <alpha | beta | rc>
```

To cancel or leave prerelease mode, try running:

```bash
yarn changeset pre exit
```
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ module.exports = {
'@babel/preset-env',
{
include: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-numeric-separator',
30 changes: 16 additions & 14 deletions docs/API/additional-exports.mdx
Original file line number Diff line number Diff line change
@@ -3,17 +3,19 @@ title: Additional Exports
nav: 9
---

| export | usage |
| -------------- | -------------------------------------------------------------- |
| addEffect | Adds a global render callback which is called each frame |
| addAfterEffect | Adds a global after-render callback which is called each frame |
| addTail | Adds a global callback which is called when rendering stops |
| invalidate | Forces view global invalidation |
| advance | Advances the frameloop (given that it's set to 'never') |
| extend | Extends the native-object catalogue |
| createPortal | Creates a portal (it's a React feature for re-parenting) |
| createRoot | Creates a root that can render three JSX into a canvas |
| events | Dom pointer-event system |
| applyProps | `applyProps(element, props)` sets element properties, |
| act | usage with react-testing |
| | |
| export | usage |
| ------------------ | -------------------------------------------------------------- |
| addEffect | Adds a global render callback which is called each frame |
| addAfterEffect | Adds a global after-render callback which is called each frame |
| addTail | Adds a global callback which is called when rendering stops |
| flushGlobalEffects | Flushes global render-effects for when manually driving a loop |
| invalidate | Forces view global invalidation |
| advance | Advances the frameloop (given that it's set to 'never') |
| extend | Extends the native-object catalogue |
| createPortal | Creates a portal (it's a React feature for re-parenting) |
| createRoot | Creates a root that can render three JSX into a canvas |
| events | Dom pointer-event system |
| applyProps | `applyProps(element, props)` sets element properties, |
| act | usage with react-testing |
| useInstanceHandle | Exposes react-internal local state from `instance.__r3f` |
| | |
82 changes: 42 additions & 40 deletions docs/API/canvas.mdx
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ const App = () => (
<Canvas>
<pointLight position={[10, 10, 10]} />
<mesh>
<sphereBufferGeometry />
<sphereGeometry />
<meshStandardMaterial color="hotpink" />
</mesh>
</Canvas>
@@ -23,22 +23,26 @@ const App = () => (

## Render Props

| Prop | Description | Default |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| children | three.js JSX elements or regular components | |
| gl | Props that go into the default renderer, or your own renderer. Also accepts a synchronous callback like `gl={canvas => new Renderer({ canvas })}` | `{}` |
| camera | Props that go into the default camera, or your own `THREE.Camera` | `{ fov: 75, near: 0.1, far: 1000, position: [0, 0, 5] }` |
| shadows | Props that go into `gl.shadowMap`, can also be set true for `PCFsoft` | `false` |
| raycaster | Props that go into the default raycaster | `{}` |
| frameloop | Render mode: always, demand, never | `always` |
| resize | Resize config, see react-use-measure's options | `{ scroll: true, debounce: { scroll: 50, resize: 0 } }` |
| orthographic | Creates an orthographic camera | `false` |
| dpr | Pixel-ratio, use `window.devicePixelRatio`, or automatic: [min, max] | `[1, 2]` |
| legacy | Enables THREE.ColorManagement.legacyMode in three r139 or later | `false` |
| linear | Switch off automatic sRGB encoding and gamma correction | `false` |
| flat | Use `THREE.NoToneMapping` instead of `THREE.ACESFilmicToneMapping` | `false` |
| onCreated | Callback after the canvas has rendered (but not yet committed) | `(state) => {}` |
| onPointerMissed | Response for pointer clicks that have missed any target | `(event) => {}` |
| Prop | Description | Default |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| children | three.js JSX elements or regular components | |
| gl | Props that go into the default renderer, or your own renderer. Also accepts a synchronous callback like `gl={canvas => new Renderer({ canvas })}` | `{}` |
| camera | Props that go into the default camera, or your own `THREE.Camera` | `{ fov: 75, near: 0.1, far: 1000, position: [0, 0, 5] }` |
| scene | Props that go into the default scene, or your own `THREE.Scene` | `{}` |
| shadows | Props that go into `gl.shadowMap`, can be set true for `PCFsoft` or one of the following: 'basic', 'percentage', 'soft', 'variance' | `false` |
| raycaster | Props that go into the default raycaster | `{}` |
| frameloop | Render mode: always, demand, never | `always` |
| resize | Resize config, see react-use-measure's options | `{ scroll: true, debounce: { scroll: 50, resize: 0 } }` |
| orthographic | Creates an orthographic camera | `false` |
| dpr | Pixel-ratio, use `window.devicePixelRatio`, or automatic: [min, max] | `[1, 2]` |
| legacy | Enables THREE.ColorManagement in three r139 or later | `false` |
| linear | Switch off automatic sRGB color space and gamma correction | `false` |
| events | Configuration for the event manager, as a function of state | `import { events } from "@react-three/fiber"` |
| eventSource | The source where events are being subscribed to, HTMLElement | `React.MutableRefObject<HTMLElement>`, `gl.domElement.parentNode` |
| eventPrefix | The event prefix that is cast into canvas pointer x/y events | `offset` |
| flat | Use `THREE.NoToneMapping` instead of `THREE.ACESFilmicToneMapping` | `false` |
| onCreated | Callback after the canvas has rendered (but not yet committed) | `(state) => {}` |
| onPointerMissed | Response for pointer clicks that have missed any target | `(event) => {}` |

## Render defaults

@@ -50,7 +54,7 @@ Canvas uses [createRoot](#createroot) which will create a translucent `THREE.Web

and with the following properties:

- outputEncoding = THREE.sRGBEncoding
- outputColorSpace = THREE.SRGBColorSpace
- toneMapping = THREE.ACESFilmicToneMapping

It will also create the following scene internals:
@@ -60,7 +64,7 @@ It will also create the following scene internals:
- A `THREE.PCFSoftShadowMap` if `shadows` is true
- A `THREE.Scene` (into which all the JSX is rendered) and a `THREE.Raycaster`

In recent versions of threejs, `THREE.ColorManagement.legacy` will be set to false to enable automatic conversion of colors according to the renderer's configured color space. R3F will handle texture encoding conversion. For more on this topic, see [https://threejs.org/docs/#manual/en/introduction/Color-management](https://threejs.org/docs/#manual/en/introduction/Color-management).
In recent versions of threejs, `THREE.ColorManagement.enabled` will be set to `true` to enable automatic conversion of colors according to the renderer's configured color space. R3F will handle texture color space conversion. For more on this topic, see [https://threejs.org/docs/#manual/en/introduction/Color-management](https://threejs.org/docs/#manual/en/introduction/Color-management).

## Custom Canvas

@@ -73,34 +77,32 @@ Roots have the same options and properties as `Canvas`, but you are responsible
Creates a root targeting a canvas, rendering JSX.

```jsx
import { createRoot, events } from '@react-three/fiber'
import * as THREE from 'three'
import { extend, createRoot, events } from '@react-three/fiber'

let root
// Register the THREE namespace as native JSX elements.
// See below for notes on tree-shaking
extend(THREE)

const handleResize = () => {
const size = { width: window.innerWidth, height: window.innerHeight }
// Create a react root
const root = createRoot(document.querySelector('canvas'))

// Create root with a size, events
root = createRoot(document.querySelector('canvas'), {
events,
size,
})
// Configure the root, inject events optionally, set camera, etc
root.configure({ events, camera: { position: [0, 0, 50] } })

// Render JSX
root.render(<mesh />)

// Can also tweak root root options after creation:
root.configure({ size })
// createRoot by design is not responsive, you have to take care of resize yourself
window.addEventListener('resize', () => {
root.configure({ size: { width: window.innerWidth, height: window.innerHeight } })
})

// Or to unmount and dispose of memory:
root.unmount()
}
handleResize()
// Trigger resize
window.dispatchEvent(new Event('resize'))

window.addEventListener('resize', handleResize)
// Render entry point
root.render(<App />)

// to unmount
root.unmount()
// Unmount and dispose of memory
// root.unmount()
```

## Tree-shaking
Loading