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

[WIP] Migrate to React renderer #35

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,511 changes: 1,698 additions & 1,813 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
},
"devDependencies": {
"@eslint/js": "^9.14.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"eslint": "^9.14.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-compiler": "^19.0.0-beta-63b359f-20241101",
"globals": "^15.12.0",
"type-fest": "^4.26.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"type-fest": "^4.32.0",
"typescript-eslint": "^8.12.2"
},
"dependencies": {
Expand Down
24 changes: 6 additions & 18 deletions packages/docs/mdx-components.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'
import { Application, Entity } from '@playcanvas/react'
import { OrbitControls } from '@playcanvas/react/scripts'
import { Align, Light, Anim, Camera, Collision, EnvAtlas, GSplat, Script, Render, RigidBody } from '@playcanvas/react/components'
// import { Application, Entity } from '@playcanvas/react'
// import { OrbitControls } from '@playcanvas/react/scripts'
// import { Align, Light, Anim, Camera, Collision, EnvAtlas, GSplat, Script, Render, RigidBody } from '@playcanvas/react/components'
import { Application } from '@playcanvas/react'

import ReactQueryProvider from '@/docs-components/ReactQueryProvider'

Expand All @@ -11,28 +12,15 @@ import PostEffects, { StaticPostEffects} from '@components/PostEffects'
import ShadowCatcher from '@components/ShadowCatcher'
import AutoRotate from '@components/AutoRotate'
import { MotionEntity, MotionLight } from '@components/MotionEntity'
const docsComponents = getDocsMDXComponents()

export const defaultComponents = {
ReactQueryProvider,
Application,
Entity,
Align, Anim, Camera, Collision, EnvAtlas, GSplat, Script, Render, RigidBody, Light,
OrbitControls,
EnvAtlasComponent,
Grid,
ShadowCatcher,
PostEffects,
StaticPostEffects,
AutoRotate,
MotionEntity,
MotionLight
Application
}

export function useMDXComponents(components) {
return {
...components,
...defaultComponents,
...docsComponents
...defaultComponents
}
}
2 changes: 1 addition & 1 deletion packages/docs/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
7 changes: 5 additions & 2 deletions packages/docs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const withNextra = nextra({
contentDirBasePath: '/playground',
})

export default withNextra({
const nextConfig = {
reactStrictMode: true,
transpilePackages: ['next-mdx-remote-client', 'playcanvas'],
async headers() {
Expand Down Expand Up @@ -45,4 +45,7 @@ export default withNextra({
permanent: true
}
]
})
}

export default nextConfig
// export default withNextra(nextConfig)
4 changes: 2 additions & 2 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"motion": "^11.13.1",
"next": "^15.0.2",
"next-mdx-remote-client": "^1.0.3",
"nextra": "^4.0.0-app-router.34",
"nextra-theme-docs": "^4.0.0-app-router.30",
"nextra": "^4.0.0-app-router.42",
"nextra-theme-docs": "^4.0.0-app-router.42",
"playcanvas": "^2.3.3",
"react": "^18.3.1",
"react-codesandboxer": "^3.1.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getPageMap } from 'nextra/page-map'
import './globals.css'
import { CodeXml } from 'lucide-react'
import ReactQueryProvider from '@/docs-components/ReactQueryProvider'
import { Application, PlayCanvasCanvas } from '@playcanvas/react'

export const { viewport } = Head

Expand Down Expand Up @@ -64,6 +65,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
pageMap={await getPageMap()}
>
<ReactQueryProvider>
{/* {className='hover:cursor-grab active:cursor-grabbing w-full'} */}
{children}
</ReactQueryProvider>
</Layout>
Expand Down
19 changes: 16 additions & 3 deletions packages/docs/src/app/docs/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,22 @@ import { Tabs, Code } from 'nextra/components'
<Tabs.Tab>
<div className='w-full aspect-video rounded-xl overflow-hidden'>
<ReactQueryProvider>
<Application className='hover:cursor-grab active:cursor-grabbing w-full' fillMode="NONE" resolutionMode="AUTO">
<Example />
</Application>
{/* <Application fillMode="NONE" resolutionMode="AUTO">
<entity name='root'>
<entity name='camera' key='a' position={[0, 0, 20]}>
<camera/>
</entity>
<entity name='child' key='b'>
<render type='box' />
</entity>
</entity>
</Application> */}
{/* <PlayCanvasCanvas className='hover:cursor-grab active:cursor-grabbing w-full' fillMode="NONE" resolutionMode="AUTO">
<pcentity name="ParentEntity">
<pcentity name="ChildEntity" />
<pcentity name="OtherChildEntity" />
</pcentity>
</PlayCanvasCanvas> */}
</ReactQueryProvider>
</div>
</Tabs.Tab>
Expand Down
13 changes: 13 additions & 0 deletions packages/docs/src/app/sandbox/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ReactQueryProvider from "@/docs-components/ReactQueryProvider";

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<ReactQueryProvider>
{children}
</ReactQueryProvider>
</body>
</html>
)
}
139 changes: 139 additions & 0 deletions packages/docs/src/app/sandbox/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"use client"

import { Application } from "@playcanvas/react";
import { useApp } from "@playcanvas/react/hooks";
import { fetchAsset } from "@playcanvas/react/utils";
import { FILLMODE_FILL_WINDOW, FILLMODE_KEEP_ASPECT, Script, TEXTURETYPE_RGBP } from "playcanvas";
import { useEffect, useRef, useState } from "react";

let cnt = 0


// import { TEXTURETYPE_RGBP } from "playcanvas"
// import { useApp } from "@playcanvas/react/hooks"
import { useQuery } from "@tanstack/react-query";
// import { fetchAsset } from "@playcanvas/react/utils"

/**
* Loads an asset using react-query
*
* @param {string} src - The URL of the texture asset.
* @param {Object} [props] - Additional properties to pass to the asset loader.
* @returns {{ data: Asset, isPending: boolean }} - The texture asset and its loading state.
*/
export const useAsset = (src, type, props) => {
const app = useApp();
const queryKey = [app.root?.getGuid(), src, type, props];

// Construct a query for the asset

// return null
return useQuery({
queryKey,
queryFn: () => app && fetchAsset(app, src, type, props)
})
}

/**
* Loads a texture asset as an environment atlas
*
* @param {string} src - The URL of the texture asset.
* @param {Object} [props] - Additional properties to pass to the asset loader.
* @returns {{ data: Asset, isPending: boolean, release: Function }} - The texture asset and its loading state.
*/
export const useEnvAtlas = (src : string, props = {}) => useAsset(src, 'texture', {
...props,
type: TEXTURETYPE_RGBP, mipmaps: false
});

export const useSplat = (src : string, props = {}) => useAsset(src, 'gsplat', props);

/**
* Loads a glb asset
*
* @param {string} src - The URL of the glb.
* @param {Object} [props] - Additional properties to pass to the asset loader.
* @returns {{ data: Asset, isPending: boolean, release: Function }} - The GLB asset and its loading state.
*/
export const useModel = (src : string, props = {}) => useAsset(src, 'container', props);


/**
* Loads a texture asset
*
* @param {string} src - The URL of the texture asset.
* @param {Object} [props] - Additional properties to pass to the asset loader.
*/
export const useTexture = (src : string, props = {}) => useAsset(src, 'texture', props);


class Spinner extends Script {
initialize() {
// cnt++
this.seed = Math.round(Math.random() * 100)
// console.log('initialize', cnt)

// this.on('destroy', () => {
// cnt--
// console.log('destroy', cnt)
// })
}
update(dt) {
this.entity.rotate(0, dt * 100 * this.speed, 0)
console.log('update', this.seed, this.speed)
}
}

const Content = ({ fov, z, speed, runScript }: { fov: number, z: number, speed: number, runScript: boolean }) => {

// const { data } = useModel('/t-rex.glb');

const entityRef = useRef<pc.Entity | null>(null)
const cameraRef = useRef<pc.CameraComponent | null>(null)
// const divRef = useRef<HTMLDivElement | null>(null)


// useEffect(() => {
// console.log(fov, z, entityRef.current)

// })

return <>
<entity key='sd' name="root" ref={entityRef} sdfsd='sd'>
<entity name="camera" position={[0, 0, z]} enabled >
{/* <anim bse='sdf' /> */}
<camera fov={fov} bse='sdf' sdf='sdf'/>
{/* <chips/>
<add/> */}
</entity>
<entity name="light" rotation={[0, 0, 45]}>
<light type="directional" />
</entity>
<entity name="child" position={[1, 0, 0]} >
<render type="box" />
{ runScript && <script script={Spinner} speed={speed} /> }
</entity>
</entity>
</>
}


export default function Sandbox({ children }: { children: React.ReactNode }) {

const [z, setZ] = useState(20)
const [fov, setFov] = useState(20)
const [speed, setSpeed] = useState(1)
const [runScript, setRunScript] = useState(true)

console.log('sandbox',fov, z, speed)

return <div>
<button onClick={() => setZ(Math.random() * 10 + 4)}>Change Z</button>
<button onClick={() => setFov(Math.random() * 10 + 30)}>Change FOV</button>
<button onClick={() => setSpeed(Math.random())}>Change Speed</button>
<button onClick={() => setRunScript(!runScript)}>{ runScript ? 'Disable Script' : 'Enable Script' }</button>
<Application>
<Content fov={fov} z={z} speed={speed} runScript={runScript}/>
</Application>
</div>
}
3 changes: 2 additions & 1 deletion packages/docs/src/components/AutoRotate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { AutoRotator } from "@playcanvas/react/scripts";
import { FC } from "react";

const AutoRotate: FC<Record<string, unknown>> = (props) => {
return <Script script={AutoRotator} {...props} />
// return <Script script={AutoRotator} {...props} />
return null
}

export default AutoRotate;
25 changes: 13 additions & 12 deletions packages/docs/src/components/EnvAtlas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import { FC, useLayoutEffect } from "react";
import { useEnvAtlas } from "./hooks/use-asset";
import type { Asset } from "playcanvas";
import { EnvAtlas } from "@playcanvas/react/components";
import { useApp } from "@playcanvas/react/hooks";
// import { EnvAtlas } from "@playcanvas/react/components";
// import { useApp } from "@playcanvas/react/hooks";

type EnvAtlasComponentsProps = {
src: string;
Expand All @@ -13,19 +13,20 @@ type EnvAtlasComponentsProps = {

const EnvAtlasComponent: FC<EnvAtlasComponentsProps> = ({ src, intensity = 1, ...props }) => {

const app = useApp();
// const app = useApp();

useLayoutEffect(() => {
const layer = app?.scene?.layers?.getLayerByName('Skybox');
if(layer){
layer.enabled = false;
}
app.scene.skyboxIntensity = intensity;
}, [app]);
// useLayoutEffect(() => {
// const layer = app?.scene?.layers?.getLayerByName('Skybox');
// if(layer){
// layer.enabled = false;
// }
// app.scene.skyboxIntensity = intensity;
// }, [app]);

const { data } = useEnvAtlas(src);
// const { data } = useEnvAtlas(src);

return <EnvAtlas asset={data as Asset} {...props}/>
// return <EnvAtlas asset={data as Asset} {...props}/>
return null

}

Expand Down
3 changes: 2 additions & 1 deletion packages/docs/src/components/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Grid as GridScript } from "@playcanvas/react/scripts";
import { FC } from "react";

const Grid: FC = ({ ...props }) => {
return <Script script={GridScript} {...props} />
// return <Script script={GridScript} {...props} />
return null
}

export default Grid;
Loading