Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 140 on demand rendering #497

Merged
merged 16 commits into from
Jan 23, 2024
Merged

Conversation

alvarosabu
Copy link
Member

@alvarosabu alvarosabu commented Jan 5, 2024

This PR introduces the concept of conditional rendering. It closes #140

The renderMode prop has been added to the TresCanvas component with 3 different options:

  • always the default one (current solution)
  • on-demand will automatically invalidate the frame on:
    • Instances prop changes
    • Context state change (resize, clearColor etc)
    • remove nodes (v-if)
  • manual: the invalidate method needs to be called by the user to trigger a render.

TresCanvas now emits a render event:

<TresCanvas
    render-mode="on-demand"
    clear-color="#82DBC5"
    @render="onRender"
  >

I'm still finishing the docs, you can start taking a look to it.

@alvarosabu alvarosabu marked this pull request as ready for review January 6, 2024 09:38
@alvarosabu
Copy link
Member Author

TresCanvas now emits a render event:

<TresCanvas render-mode="on-demand" clear-color="#82DBC5" @render="onRender" >

Maybe should we include an beforeRender And afterRender ?

@andretchen0
Copy link
Contributor

Hey! I'm having a look.

Maybe I just need more context, but on a first read through, I'm wondering:

For the useTres() API, would it make sense to merge advance and invalidate? Maybe under invalidate? And then accept invalidate(n?) in both on-demand and manual modes? (Currently invalidate only works in on-demand mode and console.warns otherwise.)

(My mental representation of this functionality is "mark frame as dirty", so "invalidate" makes more intuitive sense to me than "advance".)

Merging under invalidate has the slight advantage that it doesn't require a different API call if the render-mode is changed. So something like this ...

watch(() => props.myProp, invalidate)

... can just chug right along. Whereas currently, I think we'd need to switch over the render mode, e.g.:

watch(() => props.myProp, () => {
    if (renderMode === 'manual') {
        advance()
    } else if (renderMode === 'on-demand') {
        invalidate()
    }
})

@alvarosabu
Copy link
Member Author

alvarosabu commented Jan 8, 2024

Hi @andretchen0 thanks for the feedback. Honestly I had the same dilemma as you, I added the advance method just because is the same approach used by Threlte and R3F

I think is because when you are on-demand the primary role of invalidate is to signal that the scene needs to be re-rendered. It essentially "flags" the scene as invalid or dirty, indicating that something has changed and a re-render is necessary.

When invalidate is called, it doesn't directly cause the scene to render immediately. Instead, it sets up the conditions for the scene to be rendered in the next iteration of the render loop.

The advance function is used to manually progress the rendering process by one step. It's a more direct and immediate way to trigger a render and update cycle.

That being said, maybe makes more sense to change advance to directly render instead of marking a new render

 function advance() {
    if (rendererOptions.renderMode === 'manual') {
      renderer.value.render(scene.value,camera.value)
    }
    else {
      logWarning('`advance` can only be used when `renderMode` is set to `manual`')
    }
  }

Regarding switching between render mode on the fly, do you see it as a common use-case?
wdyt?

@andretchen0
Copy link
Contributor

Honestly I had the same dilemma as you, I added the advance method just because is the same approach used by Threlte and R3F

Gotcha. No problem. If other libraries are using a separate method, then maybe there's a good reason.

Regarding switching between render mode on the fly, do you see it as a common use-case?
wdyt?

I don't see it as a common use case, but people are surprising! ;)

@alvarosabu
Copy link
Member Author

Hi @andretchen0 and @Tinoooo, I'm currently facing some performance issues on the devtools (creating the scene graph and reactivity) because I'm sending an event to the devtools every time it renders.

Should we set "on-demand" rendering as default? wdyt?

@thomasaull
Copy link

Maybe a fourth mode would make sense, where the render stops, when the current tab/window is not active anymore. This would prevent the scene rendering in the background, eating up performance and draining the users battery. The hasFocus and/or visiblityState APIs could be used for this.

It's also worth mentioning, that vueuse has abstractions for this. If you don't want to add a dependency, maybe it could still provide some pointers etc…:

@andretchen0
Copy link
Contributor

Hi @andretchen0 and @Tinoooo, I'm currently facing some performance issues on the devtools (creating the scene graph and reactivity) because I'm sending an event to the devtools every time it renders.

Should we set "on-demand" rendering as default? wdyt?

I'd prefer "always" as the default, if possible. "always" matches my starting assumption for how rendering works: always throw away the last frame and render a new frame.

Assuming my understanding of "on-demand" is correct, I think I'd be confused if I e.g., wrote a shader and then found it wasn't updating consistently because it wasn't hooked to a prop.

Copy link
Member Author

You are right, also, we would need to refactor practically the ecosystem to be on-demand first, like OrbitControls and such.

Let's keep always.

@alvarosabu alvarosabu added the v4 label Jan 16, 2024
@alvarosabu
Copy link
Member Author

@thomasaull That is a brilliant idea, I would probably add it to one of the current states instead of a new one. ☝️

@alvarosabu
Copy link
Member Author

Maybe a fourth mode would make sense, where the render stops, when the current tab/window is not active anymore. This would prevent the scene rendering in the background, eating up performance and draining the users battery. The hasFocus and/or visiblityState APIs could be used for this.

It's also worth mentioning, that vueuse has abstractions for this. If you don't want to add a dependency, maybe it could still provide some pointers etc…:

@andretchen0 @thomasaull @Tinoooo what do you think? Should we create a new rendering mode like on-visible or add this functionality to on-demand rendering?

@thomasaull
Copy link

@andretchen0 @thomasaull @Tinoooo what do you think? Should we create a new rendering mode like on-visible or add this functionality to on-demand rendering?

Hmm, I could imagine use cases for all modes that you want to pause rendering in the background. If it were up to me I'd probably add another prop like renderInBackground or pauseRenderInBackground to TresCanvas

@andretchen0
Copy link
Contributor

Maybe a fourth mode would make sense, where the render stops, when the current tab/window is not active anymore. This would prevent the scene rendering in the background, eating up performance and draining the users battery. The hasFocus and/or visiblityState APIs could be used for this.
It's also worth mentioning, that vueuse has abstractions for this. If you don't want to add a dependency, maybe it could still provide some pointers etc…:

@andretchen0 @thomasaull @Tinoooo what do you think? Should we create a new rendering mode like on-visible or add this functionality to on-demand rendering?

Is this not the way TresCanvas works currently? If I'm understanding properly, TresCanvas uses vueuse's useRafFn, which in turn uses the browser's requestAnimationFrame. requestAnimationFrame leaves it up to the user's browser, but generally speaking, calls are paused when e.g., the tab is hidden.

(Fwiw, I mostly work on Cientos and I'm not familiar with a lot of the Tres internals, so maybe I'm not looking/tinkering in the right spot.)

@alvarosabu
Copy link
Member Author

@andretchen0 good point, you are right, I just check how many times it renders when I change tab and it stopped.

@thomasaull
Copy link

thomasaull commented Jan 19, 2024

@andretchen0 @alvarosabu In my tests with babylonjs (other engine but should be similar) this worked well, when the tab was in the background yes. But using multiple windows where the window running the engine is visible but not focused left it running at 60 FPS. Given many 3d websites/applications are very resource intensive I'd still consider adding the option to pause rendering when the tab/window is not focused.

@andretchen0
Copy link
Contributor

andretchen0 commented Jan 19, 2024

@thomasaull @alvarosabu

Given many 3d websites/applications are very resource intensive I'd still consider adding the option to pause rendering when the tab/window is not focused.

Sounds handy to me.

Maybe getting to big for this PR, but ...:

  • To piggyback on @thomasaull 's suggestion, some projects like this one include a "focus helper" feature that e.g., darkens the screen and displays a message to let the user know the window doesn't have focus and won't respond to keyboard/mouse/touch events. I've found that to be quite useful for users and even for myself during development.
  • For render modes, it'd be lovely if we had a mode where canvases stopped updating/rendering if not visible on screen, e.g., scrolled off-screen. For Cientos docs, we've started including multiple canvases on a single page in order to show off different capabilities/props. They update/render even if they can't be seen.

@alvarosabu
Copy link
Member Author

For render modes, it'd be lovely if we had a mode where canvases stopped updating/rendering if not visible on screen, e.g., scrolled off-screen. For Cientos docs, we've started including multiple canvases on a single page in order to show off different capabilities/props. They update/render even if they can't be seen.

That's why I want to consider it. But I agree with you, maybe we should create a different ticket for it. @thomasaull or @andretchen0 would you be so kind as to create a feature request?

@andretchen0 can we merge this on v4?

@andretchen0
Copy link
Contributor

For render modes, it'd be lovely if we had a mode where canvases stopped updating/rendering if not visible on screen, e.g., scrolled off-screen. For Cientos docs, we've started including multiple canvases on a single page in order to show off different capabilities/props. They update/render even if they can't be seen.

That's why I want to consider it. But I agree with you, maybe we should create a different ticket for it. @thomasaull or @andretchen0 would you be so kind as to create a feature request?

Will do.

@andretchen0 can we merge this on v4?

I'll have a look at the code later today.

Copy link
Contributor

@andretchen0 andretchen0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alvarosabu

Nice job! Looks to me like everything's working. I wasn't able to break the functionality.

The comments are either typos or some code quality stuff that you can accept or ignore – I won't block the PR. It's been lingering long enough; I don't want to stand in the way.

docs/advanced/performance.md Outdated Show resolved Hide resolved
docs/advanced/performance.md Outdated Show resolved Hide resolved
src/composables/useTresContextProvider/index.ts Outdated Show resolved Hide resolved
@@ -8,6 +8,26 @@ import { useCamera } from '../useCamera'
import type { UseRendererOptions } from '../useRenderer'
import { useRenderer } from '../useRenderer'
import { extend } from '../../core/catalogue'
import { useLogger } from '../useLogger'

export interface InternalState {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future readability/understandability, can we make this more descriptive? It's linked to renderMode, so maybe renderModeState?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andretchen0 if the name renderModeState is meant to add clarity that the property isn't just a static setting but potentially a reactive state that could change over time, then we should rename most of the properties inside the TresContext type to state, like controlsState and rendererState etc.

Imo being inside of the TresContext which is already a state implies its nature without the need to add extra verbosity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @alvarosabu

I'd be fine with dropping State off the end, as most variables are some sort of state. (But then the name renderMode will collide with the other renderMode.)

The current name – internalState – doesn't say anything about what the object is used for. Since it's about renderMode-stuff, I thought that'd make it more obvious to future readers.

But no problem leaving it as is.

Copy link
Member Author

@alvarosabu alvarosabu Jan 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andretchen0 True, internal doesn't give enough context. 🤔 Let's continue this exercise, then, what if we rename the InternalState to RenderState and add everything related to it inside?

export interface RenderState {
  mode: Ref<'always' | 'on-demand' | 'manual'>
  priority: Ref<number>
  frames: Ref<number>
  maxFrames: number
  canBeInvalidated: ComputedRef<boolean>
  invalidate: () => void
  advance: () => void
}

I think it would be cleaner.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!

* If set to 'always', the scene will be rendered every frame
*/
renderMode: Ref<'always' | 'on-demand' | 'manual'>
internal: InternalState
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the type, can we make this field name more descriptive? Maybe renderModeState?

src/core/nodeOps.ts Outdated Show resolved Hide resolved
docs/advanced/performance.md Outdated Show resolved Hide resolved
@alvarosabu
Copy link
Member Author

Hey, buddy @andretchen0 I refactored internal for render, what do you think?

@andretchen0
Copy link
Contributor

Hey, buddy @andretchen0 I refactored internal for render, what do you think?

Hey! I think that's clearer than internal. You?

@alvarosabu
Copy link
Member Author

Way better

@alvarosabu alvarosabu merged commit f688c64 into v4 Jan 23, 2024
3 checks passed
@alvarosabu alvarosabu mentioned this pull request Mar 20, 2024
Closed
13 tasks
alvarosabu added a commit that referenced this pull request May 30, 2024
* feat: 474 vue chrome devtools plugin (#479)

* feat: vue chrome devtools

* feat: editable scenes from devtools

* chore(lint): fix lint errors

* feat: highlight material

* chore(lint): fix

* chore: release v4.0.0-next.0

* feat: update to three `v160` and vue `v3.4` (#488)

* fix(types): added `Object3DEventMap` to `Object3D` generics for point event handling (#491)

* feat: 140 on demand rendering (#497)

* feat: conditional rendering

* chore: remove subscribe system

* feat: on-demand automatic invalidation with prop changes

* feat: invalidate once first when is `renderMode !== 'always'`

* docs: performance page, on-demand rendering

* chore: fix windowsize issue

* chore(lint): fix maximum line length issues

* feat: invalidate on-demand on window resize

* feat: add advance method for manual mode

* feat: fix manual first render with advance

* docs: performance manual mode

* docs: add badge with version

* chore: correct typos and PR suggestions

* chore: tell dont ask fix

* feat: render state instead of internal

* feat: remove default camera warning (#499)

* feat: remove annoying defautl camera warning

* chore: remove logWarning

* feat: 492 set tone mapping default to acesfilmictonemapping (#498)

* feat: set ACESFilmicToneMapping as default toneMapping

* chore: usage of nullish coealescing operator instead of ternaries

* feat: 516 localstate for custom renderer node instances instead of userdata (#522)

* feat: conditional rendering

* chore: remove subscribe system

* feat: on-demand automatic invalidation with prop changes

* feat: invalidate once first when is `renderMode !== 'always'`

* docs: performance page, on-demand rendering

* chore: fix windowsize issue

* chore(lint): fix maximum line length issues

* feat: invalidate on-demand on window resize

* feat: add advance method for manual mode

* feat: fix manual first render with advance

* docs: performance manual mode

* docs: add badge with version

* chore: correct typos and PR suggestions

* chore: tell dont ask fix

* feat: render state instead of internal

* feat: add __tres local state to nodeOps instances

* feat: add context to root on instances localstate

* feat: camera registration ops from node local state ctx

* feat: event handling registration from localState of nodes

* feature: disposable flag on node localstate

* feat: remove userData from types

* chore: remove unused import

* fix(test): fake localstate `.__tres` on tests

* fix(types): fix nodeOps instances localstate type

* fix: camera aspect

* Update orthographic camera aspect when screen size updates
* Give user a "manual" flag to keep Tres from updating camera

* feat: 503 conditional rendering of primitives (#514)

* feat(nodeOps): switch instance logic for reactive `object` prop

* chore: playground primitives with models

* chore: fix linter

* chore: fix tests and linters, primitive object is now reactive

* chore: refactor instance swaping logic to overwrite set and copy properties

* chore: tests

* chore: remove console.log

* chore: remove unused import watch

* feat: add primitive conditional to patch object prop

* fix: `nodeOps` is now a function (#579)

* fix: `nodeOps` is now a function

* chore(test): updated tests for `nodeOps`

* chore: next package json version

* chore: release v4.0.0-next.1

* fix: refactor nodeOps to return methods at the end of the function (#602)

* fix: refactor nodeOps to return methods at the end of the function

* chore: fix lint

* chore: internal playground organisation (#601)

* chore: new internal playground org and testing pages

* chore: fix lint

* chore: better styling of playground landing page

* chore: lint

* chore: deps update

* chore: internal primitive model test playground

* chore: fix lint

* chore: release v4.0.0-next.2

* chore: misc routes

* fix: do not change pierced props case (#608)

* chore: lint fix

* chore: problem with package version

* chore: fix lint

* chore: rebuild pnpm-lock

* test(nodeOps): clean up tests

* test(nodeOps): organize tests

* test: add coverage plugin

* test: add coverage to package.json script

* test(nodeOps): improve test coverage

* feat: devtools renderer improvements (#614)

* feat: renderer programs when selecting scene on devtools

* feat: renderer.info

* chore: fix lint

* docs: devtools update

* chore: fix lint issues

* feat(events)!: pointerevents manager and state (#529)

* new file:   playground/src/components/Box.vue
	new file:   playground/src/pages/raycaster/Propogation.vue
	  * Started work on interactive Event Propogation playground example
	modified:   src/components/TresCanvas.vue
	  * Import and use `useEventStore`
	  * defineEmits for all expected pointer events so we may emit propogated events off of the canvasa
	modified:   src/composables/index.ts
	new file:   src/composables/useEventStore/index.ts
	  * Started work on an event store. I'm not sure this counts as a store just yet
	  * Wired up majority of pointer events
	  * Added event propogation
	  * Does not require using userData scene props or nodeOps for registering objects to scene
	modified:   src/composables/useRaycaster/index.ts
	  * Added new event listeners to power newly supported pointer events. We now check whole scene/children when calling intersectObjects.
	  * Created new EventHooks for new events
	  * Added `forceUpdate` function that allows for pointer-move events to work without mouth movement (good for when camera is moving but mouse is not)

	modified:   src/core/nodeOps.ts
	  * Added supported events to array so they don't get received as props
	  * (temporarily) unhook current pointer event solution to iterate on useEventStore
	modified:   src/utils/index.ts
	  * Added Camel-to-kebab case util

* Support multiple event listeners, add support for .stop event modifier

* Set stopProgation variable to false by default, whoops

* fix typo

* fix: remove `createGlobalState` from `useEventStore`, allowing events to work while multiple TresCanvas' are being used

* fix(perf): remove extraneous intersectObjects/getIntersects calls by moving intersects into a ref that is updated on pointer-move

* chore(lint): fix lint issues

* feat: enhance events manager to include duplicates checking, pointer-missed support, and forced updating

Per file changelog:
	modified:   playground/src/components/Box.vue
	  * Added a pointer-missed handler for testing
	modified:   playground/src/pages/TheBasic.vue
	  * uses forceUpdate from EventManager to fire events even when the mouse hasn't moved
	modified:   playground/src/pages/raycaster/Propagation.vue
	  * Didn't mean to undo the lint changes, adds a pointer-missed event on the canvas 		for extra testing
	modified:   src/components/TresCanvas.vue
	  * Adds `pointer-missed` as possible event for canvas emits
	modified:   src/composables/index.ts
	  * Update export
	deleted:    src/composables/useEventStore/index.ts
	  * Rename `useEventStore` to `useTresEventManager`
	modified:   src/composables/useRaycaster/index.ts
	  * Check for empty intersects on hit test, wire up pointerMissed events eventHook
	  * Fix forceUpdate to call onPointerMove instead of triggering an EventHook
	modified:   src/composables/useTresContextProvider/index.ts
	  * Add TresEventManager type
	new file:   src/composables/useTresEventManager/index.ts
	  * add onPointerMissed
	  * create (de)registerPointerMissedObj methods so we can track objects in the scene listening to this event
	  * Note: These are passed to nodeOps via TresContext
	  * Implement duplicates checking for eventPropogation
	modified:   src/core/nodeOps.ts
	  * register/deregister pointerMissed objects

* chore: lint

* docs: new event docs

* chore: fix lint

* feat: enhance event object details and use in Box example to change material color. Add ability to force event system updates even when mouse hasn't moved. Enhance pointer-enter/leave events. Update types

  Box.vue
    * Added pointer-missed handler
    * set the materials flash color using the object coming off of the event instead of a ref
  UseRaycaster
    * Flesh out event details to include
      * all mouse event properties
      * intersections
      * tres camera
      * camera raycaster
      * source event
      * mouse position delta
      * stopPropagating stub
      * and unprojectedPoint (this needs work, cant get the math to work)
  UseTresContextProvider
    * Add TresEventManager type to TresContext
  useTresEventManager
    * Add forceUpdate method to allow apps to force an event system update even when the mouse hasnt moved
    * Add pointerMissed event
    * Properly implement pointer-enter/pointer-leave events
      * Before now, pointer-enter | leave were only called on first object in intersection, now we execute the events for all entered/left objects
    * Use stopPropagating property included on event object

* chore: lint

* chore: fix lint issues

---------

Co-authored-by: alvarosabu <[email protected]>

* feat: 499 better memory management (#606)

* chore: memory management playground

* feat: recursively free cpu and gpu memory allocation on remove

* chore: clumsy attempt to dispose on unmount

* chore: lint fix

* feat: remove scene root on disposal

* chore: fix lint

* docs: added disposal guide on `performance` docs

* chore: fix lint

* chore: type issues (#663)

* fix: fix some internal types

* chore: fix linters

* fix: typescript issues on event manager

* chore: release v4.0.0-rc.0

* fix: make on* callbacks settable (#672)

* fix: make on- callbacks settable

* test: test setting not calling

* feat: 633 use loop  (#673)

* feat: createRenderLoop unique to context

* feat: onLoop returns current state

* feat: ensuring callback excecution with index order

* feat: take control of render loop logic

* docs: updated composable docs

* feat: change error to deprecation warning towards v5

* chore: add link to new composable docs on deprecation warning

* chore: remove depcreation warning of existing useRenderLoop

* feat: `useFrame` and `useRender` instead of `onLoop`

* chore: fix lint

* feat: applied useFrame to directives

* chore: fix lint

* feat: `useUpdate` instead of `useFrame` and useRender pausing.

* chore: testing fbo

* feat: reserve index 1 for late-updates

* chore: fix lint

* feat: useLoop composable for the win

* chore: change onLoop name for register

* chore: unit tests for loop

* chore: change order for registration to make index optional

* chore: fix lint

* feat: pauseRender and resumeRender

* docs: useLoop guide

* docs: updated basic animations recipe to `useLoop`

* docs: correct pause render methods on docs

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* chore: refactor subscribers to `priorityEventHooks`

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* feat: just return `off` on the loop registration methods

* docs: update docs to add `off` unregister callback method

* feat: remove `v-rotate`

* docs: added context warning for `v-always-look-at`

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* Update docs/api/composables.md

Co-authored-by: Tino Koch <[email protected]>

* chore: remove leftover of isntance.provide

* chore: remove subscribers from context

* chore: abstract `wrapCallback`  and move render loop register to `useRender`

* chore: fix lint

* chore: testing off

* Revert "chore: abstract `wrapCallback`  and move render loop register to `useRender`"

This reverts commit 24cec65.

* chore: return bound `off` method and use createPriorityEvent for render with defaultFn fallback

* feat: deprecate and remove `vAlwaysLookAt` and `vRotate`

BREAKING_CHANGE: Directives `vAlwaysLookAt` and `vRotate` due incompatibility with new `useLoop` and the refactor of the render loop logic.

* feat: set context to loop to avoid wrapping the callbacks

* feat: dispose render hook before taking over

---------

Co-authored-by: Tino Koch <[email protected]>

* chore(playground): adding missing import and removing the directives that were deprecated

* chore(playground): use new composable on animations

* fix(utils): reorder object disposal to avoid issue with Helper `dispose` methods (#683)

* chore: updated deps

* chore: release v4.0.0-rc.1

* fix: manual rendering blank (#685)

* fix: increate time to advance on manual mode

* chore: correct playground

* fix: 686 useloop callback state missing controls (#687)

* fix(loop): take plain snapshots of ctx

* fix: types for useloop

* chore: lint

* docs: add RectAreaLightHelper to vLightHelper docs

* chore(deps): update deps 24-0-2024

* chore: release v4.0.0-rc.2

* fix: start loop if user calls useRenderLoop (#695)

* docs: change motivation

* chore(deps): last update before release

---------

Co-authored-by: Peter <[email protected]>
Co-authored-by: Garrett Walker <[email protected]>
Co-authored-by: Tino Koch <[email protected]>
Co-authored-by: Jaime Torrealba <[email protected]>
Co-authored-by: Jaime A Torrealba C <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants