Skip to content

Commit

Permalink
move Tunnel and Zustand dep to storybook #168
Browse files Browse the repository at this point in the history
  • Loading branch information
brianzinn committed Nov 8, 2021
1 parent 059968b commit fe8747e
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 116 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@
"react-dom": ">=17"
},
"dependencies": {
"react-reconciler": "^0.26.2",
"zustand": "^3.6.1"
"react-reconciler": "^0.26.2"
}
}
1 change: 0 additions & 1 deletion src/customComponents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
// export {default as ModelLifecycleListener} from "../customHosts/ModelLifecycleListener"
export {default as Skybox} from "./Skybox";
export {default as Model} from "./Model";
export {default as createTunnel} from "./Tunnel";
export {default as Html} from "./Html";
3 changes: 2 additions & 1 deletion storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"pixi.js": "^6.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"storybook": "^6.3.7"
"storybook": "^6.3.7",
"zustand": "^3.6.4"
}
}
92 changes: 0 additions & 92 deletions storybook/stories/babylonjs/Basic/tunnel.stories.js

This file was deleted.

38 changes: 18 additions & 20 deletions storybook/stories/babylonjs/GUI/html.stories.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, {useEffect, useState} from 'react'
import '@babylonjs/inspector'
import {Engine, Scene, Html} from 'react-babylonjs'
import {Vector3} from '@babylonjs/core/Maths/math'
import '../../style.css'
import React, { useEffect, useState } from 'react';
import { Engine, Scene, Html } from 'react-babylonjs';
import { Vector3 } from '@babylonjs/core/Maths/math';
import '../../style.css';

export default { title: 'GUI' };

Expand Down Expand Up @@ -41,26 +40,25 @@ function WithHtmlText() {
}, []);

return (
<transformNode name="transform-node" position={position} rotation={rotation}>
<sphere name='sphere1' diameter={2} segments={16}
position={new Vector3(0, 1, 0)}>
<Html name="html" center occlude={false} >
{<p>Text</p>}
</Html>
</sphere>
</transformNode>
<transformNode name="transform-node" position={position} rotation={rotation}>
<sphere name='sphere1' diameter={2} segments={16}
position={new Vector3(0, 1, 0)}>
<Html name="html" center occlude={false} >
{<div style={{ backgroundColor: 'white', borderRadius: '5px', border: '3px solid red', padding: '8px' }}>Text</div>}
</Html>
</sphere>
</transformNode>
)
}

export const HtmlText = () => (
<div style={{flex: 1, display: 'flex'}}>
<div style={{ flex: 1, display: 'flex' }}>
<Engine antialias adaptToDeviceRatio canvasId='babylonJS'>
<Scene>
<freeCamera name='camera1' position={new Vector3(0, 5, -10)}
setTarget={[Vector3.Zero()]}/>
<hemisphericLight name='light1' intensity={0.7} direction={Vector3.Up()}/>
<WithHtmlText/>
</Scene>
<Scene>
<freeCamera name='camera1' position={new Vector3(0, 5, -10)} setTarget={[Vector3.Zero()]} />
<hemisphericLight name='light1' intensity={0.7} direction={Vector3.Up()} />
<WithHtmlText />
</Scene>
</Engine>
</div>
)
File renamed without changes.
151 changes: 151 additions & 0 deletions storybook/stories/babylonjs/Integrations/tunnel.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React, { useEffect, useRef, useState, Fragment } from 'react';
import create from "zustand";
import { Engine, Scene, useBeforeRender } from 'react-babylonjs';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import { Color3 } from '@babylonjs/core/Maths/math.color';

import '../../style.css';

export default { title: 'Integrations' };

/**
* This is a javascript port of ./Tunnel.tsx
*/
const createTunnel = () => {

const useStore = create((set, get) => ({
store: {},
add: (key, el) => set((state) => {
return { ...state, store: { ...state.store, [key]: el } }
}),
remove: (key) => set((state) => {
if (key in state.store) {
delete state.store[key]
}
return { ...state, store: { ...state.store } }
})
}))

/**
* Tunnel Entrance
* @param uid a unique identifier - similar to key. if same uid exists in app, only one tunnel entrance will end in tunnel exit
* @returns nothing
*/
const TunnelEntrance = ({ uid, children }) => {
const add = useStore(state => state.add)
const remove = useStore(state => state.remove)
useEffect(() => {
add(uid, children);
return () => {
remove(uid)
}
}, [children])

return <></>
}

/**
* Tunnel Exit
* @param uids optionally add uids of tunnel entrances to only show components of these entrances
* @returns Components of Tunnel Entrance
*/
const TunnelExit = ({ uids }) => {
const state = useStore(state => state.store)

return <>{Object.keys(state)
.filter(key => uids ? uids.includes(key) : true)
.map((key) => {
return <Fragment key={key}>
{state[key]}
</Fragment>
})
}
</>
}

return { TunnelEntrance, TunnelExit };
}

/**
* A tunnel allows to render components of one renderer inside another.
* I.e. babylonjs components normally need to live within Engine component.
* A tunnel entrance allows to position components in a different renderer, such as ReactDOM
* and move it to the tunnel exit, that must exist within Engine component.
*
* The nice thing is, even refs can be used outside of Engine context.
*
* The createTunnel function creates a tunnel entrance and exit component.
* The tunnel works one-directional.
* TunnelEntrance only accepts components that are allowed to live within the renderer of TunnelExit.
* Multiple entrances and exits are possible.
*
* If components need to be rendererd the other way around, a second Tunnel is needed.
*
*/
const { TunnelEntrance, TunnelExit } = createTunnel();

const rpm = 5;

const WithTunnel = ({ uids }) => {
const [_, setReady] = useState(false);
const ref = useRef(null);
useBeforeRender((scene) => {

if (ref.current !== null) {
const deltaTimeInMillis = scene.getEngine().getDeltaTime();
ref.current.rotation.y += ((rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000));
}
})

useEffect(() => {
setReady(true);
}, [ref.current])

return <transformNode name="transform-node" ref={ref}>
<TunnelExit uids={uids} />
</transformNode>
}

export const ZustandTunnel = () => {

/** ref to tunnel is possible */
const ref = useRef(null)

const [position, setPosition] = useState(1)

useEffect(() => {
if (ref.current) {
ref.current.position.x = Math.abs(position - 4);
}
}, [position])

return <>
<div style={{ flex: 1, display: 'flex' }}>
<button onClick={() => setPosition(Math.abs(position - 1))}>Set Position</button>
</div>
<div style={{ flex: 1, display: 'flex' }}>
{/** Multiple Tunnel Entrances */}
<TunnelEntrance uid="hyperloop">
<box name="box" ref={ref} position={new Vector3(0, position, 0)}>
<standardMaterial name="mat" diffuseColor={Color3.Blue()} specularColor={Color3.Black()} />
</box>
</TunnelEntrance>
<TunnelEntrance uid="subway">
<box name="box" position={new Vector3(position, 0, 1)}>
<standardMaterial name="mat" diffuseColor={Color3.Red()} specularColor={Color3.Black()} />
</box>
</TunnelEntrance>
<Engine antialias adaptToDeviceRatio canvasId='babylonJS'>
<Scene>
<freeCamera name='camera1' position={new Vector3(0, 5, -10)}
setTarget={[Vector3.Zero()]} />
<WithTunnel uids={["subway"]} />
<transformNode name="node" position={new Vector3(5, 0, 0)}>
<WithTunnel />
</transformNode>
<hemisphericLight name='light1' intensity={0.7} direction={Vector3.Up()} />
</Scene>
</Engine>
</div>
</>
}

0 comments on commit fe8747e

Please sign in to comment.