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

Pixi React v8 #493

Open
18 of 20 tasks
trezy opened this issue Jun 15, 2024 · 14 comments
Open
18 of 20 tasks

Pixi React v8 #493

trezy opened this issue Jun 15, 2024 · 14 comments
Assignees
Labels
enhancement New feature or request released on @alpha released on @beta v8 Issues related to Pixi React v8

Comments

@trezy
Copy link
Collaborator

trezy commented Jun 15, 2024

Overview

This issue will track progress on version 8 of Pixi React. This new major version is a complete rewrite of the library and will support Pixi.js v8.

Thesis

The v7 codebase of Pixi React has served its purpose, but it has become burdensome to maintain. Especially with the release of Pixi.js v8 and the significant number of breaking changes it introduced, it makes more sense to rebuild this library from scratch than to continue supporting the legacy codebase.

For this complete rewrite, we'll take a new approach to the library's implementation by introducing a custom React Pixi pragma, an extend API, and reflecting all Pixi components as React components. This rewrite is heavily influenced by the prior art of @react-three/fiber, and I've been receiving significant help from @CodyJasonBennett and @krispya.

A new pragma

React allows custom reconcilers to tap into its re/rendering logic. React Pixi has been using a custom reconciler for some time, but the library provided custom components that used this reconciler to manage their own rendering lifecycle. These components need to be maintained, and their logic could require changes depending on how the core Pixi.js library changed.

With a new JSX pragma, we can eliminate the need for custom components. Instead, we reflect Pixi.js components directly into the pragma and proxy their JSX props back as Pixi.js component props. This allows us to expose all Pixi.js components now and in the future with no changes to React Pixi.

The extend API

To provide all components as a pragma would typically require us to import the entirety of Pixi.js into the Pixi React library, making tree shaking difficult and significantly increasing the build size for anybody trying to use Pixi.js v8. Instead, we're leveraging an extend API allowing users to import only the Pixi.js APIs they require, thus cutting down on bundle sizes.

The API will be available as both a Vanilla extend method and a useExtend React hook. An example of what this will look like:

import { 
  Canvas,
  useExtend,
} from '@pixi/react'
import { Sprite } from 'pixi.js'

export function App() {
  useExtend({ Sprite })

  return (
    <main>
      <Canvas>
        <sprite x={0} y={0} texture={texture} />
      </Canvas>
    </main>
  )
}

Exposing all of Pixi.js

Combining the new pragma and the extend API, we can use the entirety of Pixi.js via JSX. Any properties that you would normally set directly on a Pixi.js component will be managed via JSX props, while the components will be exposed directly through their refs. This enables lots of creative use cases, e.g. defining Pixi.js Filters in JSX...

import { 
  useEffect,
  useRef,
  useState,
} from 'react'

export function App() {
  const [filters, setFilters] = useState([])

  const filterRef = useRef(null)

  useEffect(() => {
    setFilters(previousState => {
      const filter = filterRef.current

      if (!previousState.includes(filter)) {
        return [
          ...previousState,
          filterRef.current,
        ]
      }

      return previousState
    })
  }, [])

  return (
    <>
      <blurFilter 
        ref={filterRef}
        quality={10}
        strength={10} />
      <sprite 
        filters={filters}
        texture={texture}
        x={0} 
        y={0} />
    </>
  )
}

More intuitive support down the road

The BlurFilter implementation above is a great example of something I've already got an eye towards improving. I'd like to create an attach API similar to that of @react-three/fiber, allowing non-directly-rendered components (like filters, textures, etc) to be automatically attached to their parent components. I'd also like to add support for creating Text components with normal JSX text nodes.

In short, I'd like to make the library as intuitive as possible. I'll add basic documentation for React Pixi, but the hope is that most APIs will be best served by the core Pixi.js documentation.

Development process

I've been using the dev branch as a sort of test bed for this update. Every update that's pushed to the dev branch of the repo will be deployed to the dev tag on npm. That said, these builds are not stable. Many of them will be completely broken until we're in a more stable place with the update (hopefully soon!). I do not recommend installing from the dev tag. You have been warned.

Once we're ready for user feedback, I'll post to the Official Pixi.js Discord. Make sure to join and enable notifications if you want to know when new versions are ready for testing. 😁

Tasks

  1. bug v8
    trezy
  2. bug v8
    trezy
  3. bug v8
    trezy
  4. bug v8
  5. bug released on @beta v8
    trezy
  6. enhancement released on @beta v8
    trezy
  7. released on @beta v8
    trezy
  8. enhancement v8
@trezy trezy self-assigned this Jun 15, 2024
@trezy trezy added enhancement New feature or request v8 Issues related to Pixi React v8 labels Jun 15, 2024
@trezy trezy mentioned this issue Jun 15, 2024
5 tasks
@trezy trezy pinned this issue Jun 15, 2024
@Nantris
Copy link

Nantris commented Jun 19, 2024

Thanks for your work on this @trezy!

I wonder how much the pixi/react API night change? I know the Pixi 8 API changes a bit, but I'm wondering if the next version of pixi/react is expected to have its own set of API changes on top of that?

@trezy
Copy link
Collaborator Author

trezy commented Jun 21, 2024

@Nantris: Yeah, the new API for Pixi React will be subtly different from v7. For example, here's a basic application with v7 vs the same application with v8:

// Pixi React v7
import { Container, Sprite, Stage, Text } from '@pixi/react';

export const MyComponent = () => {
  return (
    <Stage options={{ background: 0xffffff }}>
      <Sprite
        anchor={{ x: 0.5, y: 0.5 }}
        image="https://pixijs.io/pixi-react/img/bunny.png"
        x={400}
        y={270} />

      <Container x={400} y={330}>
        <Text 
          anchor={{ x: 0.5, y: 0.5 }} 
          text="Hello World" />
      </Container>
    </Stage>
  );
};
// Pixi React v8
import { Container, Sprite, Text } from 'pixi.js'
import { Application, useAsset, useExtend } from '@pixi/react';

export const MyComponent = () => {
  useExtend({ Container, Sprite, Text })

  const texture = useAsset({ src: 'https://pixijs.com/assets/bunny.png' })

  return (
    <Application background={0xffffff} >
      {texture && (
        <sprite
          anchor={{ x: 0.5, y: 0.5 }}
          texture
          x={400}
          y={270} />
      )}

      <container x={400} y={330}>
        <text 
          anchor={{ x: 0.5, y: 0.5 }} 
          text={'Hello World'} />
      </container>
    </Application>
  );
};

A few important differences to notice:

  • No more components to import
    All Pixi components are now mapped directly to JSX components. The only difference is that their JSX counterparts start with lowercase, to match the JSX paradigm that capitalized components are custom components and lowercased components are built-ins.
  • useExtend
    Because we don't import anything directly from Pixi React, we need to let Pixi React know which Pixi components are available. This allows developers to import only what they need from Pixi.js and avoid a bloated build. This hook just wraps the extend function (also exported from Pixi React v8), which is available if you'd rather declare your extends once at the root of your application.
  • useAsset
    This new hook wraps the Asset.add/Asset.load API, making it easier to load and cache assets within a Pixi React application. It also makes it possible to use <sprite> components conditionally based on the loaded state of their texture, which is necessary since Pixi.Sprite doesn't like being created without a texture.
  • <Application>, not <Stage>
    We wrap our components with <Application> component, not a <Stage> component. As with all JSX components in v8, <Application> maps 1:1 with Pixi.Application, so you can set all the same properties on it that you would when creating a new Pixi app outside of React (e.g. new Pixi.Application({ background: 0xffffff })).
  • Direct property mappings
    The sprite component uses the texture property, not the image property. As with the <Application> component, all properties are mapped 1:1 with their non-JSX counterparts. Changing these properties also works as you would expect with any other JSX component.

More additions

Once released, this syntax will always work. However, I intend to add a couple of other features that will add even more utility to the library:

  • attachAPI
    Similar to react-three-fiber, you'll eventually be able to create your dependent properties as child nodes. For example, the following component would handle creating a texture and setting it on the parent <sprite>:
    <sprite anchor={{ x: 0.5, y: 0.5 }} x={400} y={270}>
      <texture src={'https://pixijs.com/assets/bunny.png'} />
    </sprite>
  • Text nodes
    Similar to the API above, you'll eventually be able to create <text> components with a child text node, rather than setting the text property:
    <text anchor={{ x: 0.5, y: 0.5 }}>
      Hello World
    </text>
  • Custom applications
    Most Pixi applications are created with Pixi.Application, automatically creating the renderer, ticker, and a handful of other pieces that you don't need to think about. I'd like to make it easy to create your own custom Pixi applications, allowing developers to customise the application and manage the minutiae on their own.

This comment was marked as spam.

@pixijs pixijs deleted a comment from github-actions bot Jul 12, 2024

This comment was marked as spam.

@tpolito
Copy link

tpolito commented Jul 20, 2024

Just wanted to drop in and say thank you for the hard work. I've been using the v8 beta and its such a huge improvement. Very excited for the release ❤️

@danvayn
Copy link

danvayn commented Jul 23, 2024

+1 to the above. Very excited to see this drop!

@livemehere
Copy link

This is exactly the feature I wanted.
The points I found lacking in Pixi were documentation and React compatibility, and I had the same thought while using @react-three/fiber.
I’m very excited and if I can contribute in any way, I would love to!

@nightgrey

This comment was marked as off-topic.

@trezy
Copy link
Collaborator Author

trezy commented Aug 1, 2024

@nightgrey Please create a new issue with these details. Leaving it in the comments of another ticket will result in the issue being lost in the clutter.

@P3ntest
Copy link

P3ntest commented Aug 21, 2024

@trezy Thank you so much for your work! Would you say this is stable enough to start making hobby projects with it already? I would really love the new v8 performance

@trezy
Copy link
Collaborator Author

trezy commented Aug 28, 2024

@P3ntest Yup! I've been using it in hobby projects already. 😁

@AndrewJSchoen
Copy link

This looks super cool! Currently looking at this option as a replacement for our current setup with svg elements and react-spring. Any thoughts on how the new architecture would handle something like the react-spring library for elements that are reactive and dynamic, or if it would still be necessary in the first place? For example, react-three/fiber suggests that for rapidly changing values, you either use something like react-spring or their useFrame hook. Thanks!

@guillaumebrunerie
Copy link

This looks super cool! Currently looking at this option as a replacement for our current setup with svg elements and react-spring. Any thoughts on how the new architecture would handle something like the react-spring library for elements that are reactive and dynamic, or if it would still be necessary in the first place? For example, react-three/fiber suggests that for rapidly changing values, you either use something like react-spring or their useFrame hook. Thanks!

For what it's worth, I've used both pixi-react v7 and v8 in small games with a lot of animations, once with only regular React state, and once with MobX, and it worked just fine. Contrary to popular opinion, React is perfectly capable of handling 60 fps, although you might have to keep an eye on performance and optimize rerenders sometimes.

@rvion
Copy link

rvion commented Oct 20, 2024

amazing work; I personally have lots of small issues; some easy to work around, some less:

  • react contexts behave weirdly
    - I suspect react contexts are lost / not availabe in pixi subtree

  • some fishy business involving either or both Suspense and useApplication, causing un-necessary re-renders and slowing things a bit

  • some conflicts with three fiber
    - opened an issue since this is less trivial to observe than the two issues above

but it looks super promising ! thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released on @alpha released on @beta v8 Issues related to Pixi React v8
Projects
None yet
Development

No branches or pull requests

10 participants