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: v8.7.4
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: v8.8.0
Choose a head ref
  • 4 commits
  • 22 files changed
  • 2 contributors

Commits on Sep 21, 2022

  1. add permonitoring to docs

    drcmda committed Sep 21, 2022
    Copy the full SHA
    e23e095 View commit details
  2. feat(Canvas): bridge cross-container context (#2509)

    * feat(Canvas): bridge cross-container context
    
    * chore: update docs
    
    * chore(tests): add canvas integration cases
    
    * chore: remove integration tests, delegate them to v9 coverage
    CodyJasonBennett authored Sep 21, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    26cf7ee View commit details
  3. Copy the full SHA
    46d8b44 View commit details
  4. RELEASING: Releasing 2 package(s)

    Releases:
      @react-three/fiber@8.8.0
      @react-three/test-renderer@11.0.0
    
    [skip ci]
    drcmda committed Sep 21, 2022
    Copy the full SHA
    a053906 View commit details
45 changes: 0 additions & 45 deletions docs/advanced/gotchas.mdx

This file was deleted.

46 changes: 46 additions & 0 deletions docs/advanced/scaling-performance.mdx
Original file line number Diff line number Diff line change
@@ -180,6 +180,52 @@ function Model({ url }) {
}
```
## Performance monitoring
Drei has a new component [PerformanceMonitor](https://github.com/pmndrs/drei#performancemonitor) that allows you to monitor, and adapt to, device performance. This component will collect the average fps (frames per second) over time. If after a couple of iterations the averages are below or above a threshold it will trigger onIncline and onDecline callbacks that allow you to respond. Typically you would reduce the quality of your scene, the resolution, effects, the amount of stuff to render, or, increase it if you have enough framerate to fill.
Since this would normally cause ping-ponging between the two callbacks you define upper and lower framerate bounds, as long as you stay within that margin nothing will trigger. Ideally your app should find its way into that margin by gradually altering quality.
A simple example for regulating the resolution. It starts out with 1.5, if the system falls below the bounds it goes to 1, if it's fast enough it goes to 2.
```jsx
function App() {
const [dpr, setDpr] = useState(1.5)
return (
<Canvas dpr={dpr}>
<PerformanceMonitor onIncline={() => setDpr(2)} onDecline={() => setDpr(1)} >
```
You can also use the onChange callback to get notified when the average changes in whichever direction. This allows you to make gradual changes. It gives you a factor between 0 and 1, which is increased by incline and decreased by decline. The factor is initially 0.5 by default.
```jsx
import round from 'lodash/round'

const [dpr, set] = useState(1)
return (
<Canvas dpr={dpr}>
<PerformanceMonitor onChange={({ factor }) => setDpr(round(0.5 + 1.5 * factor, 1))}>
```
If you still experience flip flops despite the bounds you can define a limit of flipflops. If it is met onFallback will be triggered which typically sets a lowest possible baseline for the app. After the fallback has been called PerformanceMonitor will shut down.
```jsx
<PerformanceMonitor flipflops={3} onFallback={() => setDpr(1)}>
```
PerformanceMonitor can also have children, if you wrap your app in it you get to use usePerformanceMonitor which allows individual components down the nested tree to respond to performance changes on their own.
```jsx
;<PerformanceMonitor>
<Effects />
</PerformanceMonitor>

function Effects() {
usePerformanceMonitor({ onIncline, onDecline, onFallback, onChange })
// ...
}
```
## Movement regression
Websites like Sketchfab make sure the scene is always fluid, running at 60 fps, and responsive, no matter which device is being used or how expensive a loaded model is. They do this by regressing movement, where effects, textures, shadows will slightly reduce quality until still-stand
2 changes: 1 addition & 1 deletion docs/tutorials/basic-animations.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Basic Animations
description: This guide will help you understand refs, useFrame and how to make basic animations with Fiber
nav: 17
nav: 16
---

This tutorial will assume some React knowledge, and will be based on [this starter codesandbox](https://codesandbox.io/s/getting-started-01-12q81?from-embed), so just fork it and follow along!
2 changes: 1 addition & 1 deletion docs/tutorials/events-and-interaction.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'Events and Interaction'
description: Let's make our meshes react to user input.
nav: 14
nav: 13
---

This tutorial will assume some React knowledge, and will be based on [this starter codesandbox](https://codesandbox.io/s/getting-started-01-12q81?from-embed), so just fork it and follow along!
2 changes: 1 addition & 1 deletion docs/tutorials/how-it-works.mdx
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
title: How does it work?
description: This is an advanced guide on the inner workings of Fiber, if you are just getting started, take a
look at our introduction!
nav: 21
nav: 20
---

React Three Fiber is a React <a href="https://reactjs.org/docs/codebase-overview.html#renderers">renderer</a> for **three.js**.
2 changes: 1 addition & 1 deletion docs/tutorials/loading-models.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'Loading Models'
description: 3D Software to the web!
nav: 15
nav: 14
---

> All the models in this page were created by Sara Vieira and are freely available to download from any of the sandboxes.
2 changes: 1 addition & 1 deletion docs/tutorials/loading-textures.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'Loading Textures'
description: Let's load some fancy textures.
nav: 16
nav: 15
---

> All textures used in this chapter were downloaded from [cc0textures](https://cc0textures.com/).
2 changes: 1 addition & 1 deletion docs/tutorials/testing.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'Testing'
description: Let's test our 3D Scene
nav: 20
nav: 19
---

Like with every other application testing is an important factor when it comes to releasing an application into the wild and when it comes to React Three Fiber we can use React Three Test Renderer to achieve this.
2 changes: 1 addition & 1 deletion docs/tutorials/typescript.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Using with TypeScript
description: This guide will help through common scenarios and how to approach them with TypeScript.
nav: 19
nav: 18
---

This tutorial will assume some React and TypeScript knowledge. You can fork and follow along from [this starter codesandbox](https://codesandbox.io/s/brnsm).
2 changes: 1 addition & 1 deletion docs/tutorials/using-with-react-spring.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'Using with React Spring'
description: Animating props with ease.
nav: 18
nav: 17
---

This tutorial will assume some React knowledge, and will be based on [this starter codesandbox](https://codesandbox.io/s/interaction-98ppy?file=/src/App.js), so just fork it and follow along!
6 changes: 3 additions & 3 deletions docs/tutorials/v8-migration-guide.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 'v8 Migration Guide'
description: Changes and new features with v8 and react 18
nav: 13
nav: 12
---

Work on version 8 has begun 3 Sep 2021 and is perhaps the biggest update to Fiber yet. We've tried our best to keep breaking-changes to a minimum, they mostly affect rarely used api's like `attach`. This release brings a ton of performance related fixes, but also includes some new and ground breaking features.
@@ -218,7 +218,7 @@ This is also supported by all cameras that you create, be it a THREE.Perspective
```jsx
import { PerspectiveCamera } from '@react-three/drei'

<Canvas>
;<Canvas>
<PerspectiveCamera makeDefault manual />
</Canvas>
```
@@ -333,7 +333,7 @@ window.addEventListener('resize', () => {
root.configure({
events,
camera: { position: [0, 0, 50], fov: 50 },
size: { width: window.innerWidth, height: window.innerHeight }
size: { width: window.innerWidth, height: window.innerHeight },
})
root.render(<App />)
})
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -77,6 +77,7 @@
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-native": "0.67.4",
"react-nil": "^1.2.0",
"react-test-renderer": "^18.0.0",
"regenerator-runtime": "^0.13.9",
"three": "^0.139.0",
6 changes: 6 additions & 0 deletions packages/fiber/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @react-three/fiber

## 8.8.0

### Minor Changes

- 46d8b440: bridge cross-container context

## 8.7.4

### Patch Changes
2 changes: 1 addition & 1 deletion packages/fiber/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@react-three/fiber",
"version": "8.7.4",
"version": "8.8.0",
"description": "A React renderer for Threejs",
"keywords": [
"react",
83 changes: 83 additions & 0 deletions packages/fiber/src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { UseBoundStore } from 'zustand'
import { EventHandlers } from './events'
import { AttachType, Instance, InstanceProps, LocalState } from './renderer'
import { Dpr, RootState, Size } from './store'
import type { Fiber } from 'react-reconciler'

export type Camera = THREE.OrthographicCamera | THREE.PerspectiveCamera
export const isOrthographicCamera = (def: Camera): def is THREE.OrthographicCamera =>
@@ -30,6 +31,88 @@ export function useMutableCallback<T>(fn: T) {
return ref
}

/**
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
*/
function traverseFiber(fiber: Fiber, ascending: boolean, selector: (node: Fiber) => boolean | void): Fiber | undefined {
if (selector(fiber) === true) return fiber

let child = ascending ? fiber.return : fiber.child
while (child) {
const match = traverseFiber(child, ascending, selector)
if (match) return match

child = child.sibling
}
}

// Active contexts
const contexts: React.Context<any>[] = []

/**
* Represents a react-context bridge provider component.
*/
export type ContextBridge = React.FC<{ children?: React.ReactNode }>

/**
* React Context currently cannot be shared across [React renderers](https://reactjs.org/docs/codebase-overview.html#renderers) but explicitly forwarded between providers (see [react#17275](https://github.com/facebook/react/issues/17275)). This hook returns a {@link ContextBridge} of live context providers to pierce Context across renderers.
*
* Pass {@link ContextBridge} as a component to a secondary renderer to enable context-sharing within its children.
*/
export function useContextBridge(fiber?: Fiber): ContextBridge {
if (fiber) {
traverseFiber(fiber, true, (node) => {
const context = node.type?._context
if (!context || contexts.includes(context)) return

// In development, React will warn about using contexts between renderers because
// of the above issue. We'll hide the warning because this hook works as expected
// https://github.com/facebook/react/pull/12779
Object.defineProperties(context, {
_currentRenderer: {
get() {
return null
},
set() {},
},
_currentRenderer2: {
get() {
return null
},
set() {},
},
})

contexts.push(context)
})
}

return contexts.reduce(
(Prev, context) => {
const value = (
React as any
).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current?.readContext(context)
return (props) => React.createElement(Prev, null, React.createElement(context.Provider, { ...props, value }))
},
(props) => React.createElement(React.Fragment, props),
)
}

/**
* Exposes the current react-internal {@link Fiber}.
*/
export class FiberProvider extends React.Component<{ setFiber: React.Dispatch<Fiber>; children?: React.ReactNode }> {
private _reactInternals!: Fiber

componentDidMount() {
this.props.setFiber(this._reactInternals)
}

render() {
return this.props.children
}
}

export type SetBlock = false | Promise<null> | null
export type UnblockProps = { set: React.Dispatch<React.SetStateAction<SetBlock>>; children: React.ReactNode }

21 changes: 14 additions & 7 deletions packages/fiber/src/native/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import * as React from 'react'
import * as THREE from 'three'
import { View, ViewProps, ViewStyle, LayoutChangeEvent, StyleSheet, PixelRatio } from 'react-native'
import { ExpoWebGLRenderingContext, GLView } from 'expo-gl'
import { SetBlock, Block, ErrorBoundary, useMutableCallback } from '../core/utils'
import { SetBlock, Block, ErrorBoundary, useMutableCallback, useContextBridge, FiberProvider } from '../core/utils'
import { extend, createRoot, unmountComponentAtNode, RenderProps, ReconcilerRoot } from '../core'
import { createTouchEvents } from './events'
import { RootState, Size } from '../core/store'
@@ -44,6 +44,9 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<View, Props>(
// their own elements by using the createRoot API instead
React.useMemo(() => extend(THREE), [])

const [fiber, setFiber] = React.useState<any>(null)
const Bridge = useContextBridge(fiber)

const [{ width, height, top, left }, setSize] = React.useState<Size>({ width: 0, height: 0, top: 0, left: 0 })
const [canvas, setCanvas] = React.useState<HTMLCanvasElement | null>(null)
const [bind, setBind] = React.useState<any>()
@@ -123,9 +126,11 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<View, Props>(
},
})
root.current.render(
<ErrorBoundary set={setError}>
<React.Suspense fallback={<Block set={setBlock} />}>{children}</React.Suspense>
</ErrorBoundary>,
<Bridge>
<ErrorBoundary set={setError}>
<React.Suspense fallback={<Block set={setBlock} />}>{children}</React.Suspense>
</ErrorBoundary>
</Bridge>,
)
}

@@ -136,9 +141,11 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<View, Props>(
}, [canvas])

return (
<View {...props} ref={viewRef} onLayout={onLayout} style={{ flex: 1, ...style }} {...bind}>
{width > 0 && <GLView onContextCreate={onContextCreate} style={StyleSheet.absoluteFill} />}
</View>
<FiberProvider setFiber={setFiber}>
<View {...props} ref={viewRef} onLayout={onLayout} style={{ flex: 1, ...style }} {...bind}>
{width > 0 && <GLView onContextCreate={onContextCreate} style={StyleSheet.absoluteFill} />}
</View>
</FiberProvider>
)
},
)
Loading