11import * as React from "react" ;
22import * as THREE from "three" ;
33import { GithubLogo } from "./Ui/GithubLogo" ;
4- import { Canvas , useFrame , useThree } from "@react-three/fiber" ;
4+ import { Canvas } from "@react-three/fiber" ;
55import { XR8Controls } from "../XR8Canvas/XR8Controls" ;
6- import { useXR8 } from "../XR8Canvas/useXR8" ;
7- import { getXR8 , loadXR8 , xr8Hosted } from "../XR8Canvas/getXR8" ;
6+ import { loadXR8 , xr8Hosted } from "../XR8Canvas/getXR8" ;
87import { Game } from "./Game" ;
98import { Dice } from "./Scene/Dice" ;
10- // @ts -ignore
11- import { Visualizer } from "react-touch-visualizer" ;
129import tunnel from "tunnel-rat" ;
1310import { Ground } from "./Scene/Ground" ;
1411import { WebXRControls } from "../WebXRCanvas/WebXRControls" ;
@@ -19,15 +16,17 @@ import { TrackingHint } from "./Ui/Hints/TrackingHint";
1916import { useProgress } from "@react-three/drei" ;
2017import { useIsWebXRSupported } from "../WebXRCanvas/useWebXRSession" ;
2118import { useDelay } from "./Ui/useDelay" ;
22- import { PageRules } from "./Ui/PageRules" ;
2319import { LoadingScreen } from "./Ui/LoadingScreen" ;
20+ // @ts -ignore
21+ import { Visualizer } from "react-touch-visualizer" ;
2422
2523// @ts -ignore
2624const xr8ApiKey : string | undefined = import . meta. env . VITE_XR8_API_KEY ;
27- const touchSupported = "ontouchend" in document ;
25+ const touchSupported =
26+ typeof document !== "undefined" && "ontouchend" in document ;
2827
29- export const App = ( ) => {
30- const [ state , setState ] = React . useState <
28+ export const App = ( { loading = false } : { loading ?: boolean } ) => {
29+ let [ state , setState ] = React . useState <
3130 | { type : "loading" }
3231 | { type : "waiting-user-input" }
3332 | {
@@ -45,6 +44,9 @@ export const App = () => {
4544 | { type : "flat" }
4645 > ( { type : "waiting-user-input" } ) ;
4746
47+ // force the state to loading
48+ if ( loading ) state = { type : "loading" } ;
49+
4850 const uiTunnel = React . useMemo ( tunnel , [ ] ) ;
4951
5052 const [ error , setError ] = React . useState < Error > ( ) ;
@@ -96,107 +98,109 @@ export const App = () => {
9698
9799 const hint = useDelay ( readyForRender && ! readyForGame && "tracking" , 2500 ) ;
98100
99- if ( webXRSupported === "loading" ) return null ;
100-
101- if ( state . type === "loading" ) return null ;
102-
103101 return (
104102 < >
105- < Canvas
106- camera = { { position : new THREE . Vector3 ( 0 , 6 , 6 ) , near : 0.1 , far : 1000 } }
107- shadows
108- style = { {
109- position : "fixed" ,
110- top : 0 ,
111- left : 0 ,
112- right : 0 ,
113- bottom : 0 ,
114- touchAction : "none" ,
115- opacity : readyForRender ? 1 : 0 ,
116- } }
117- >
118- { state . type === "xr8" && state . xr8 && (
119- < XR8Controls
120- xr8 = { state . xr8 }
121- onPoseFound = { ( ) => setState ( ( s ) => ( { ...s , poseFound : true } ) ) }
122- onCameraFeedDisplayed = { ( ) =>
123- setState ( ( s ) => ( { ...s , cameraFeedDisplayed : true } ) )
124- }
125- />
126- ) }
127-
128- { state . type === "webXR" && state . webXRSession && (
129- < WebXRControls
130- worldSize = { 8 }
131- webXRSession = { state . webXRSession }
132- onPoseFound = { ( ) => setState ( ( s ) => ( { ...s , poseFound : true } ) ) }
133- onCameraFeedDisplayed = { ( ) =>
134- setState ( ( s ) => ( { ...s , cameraFeedDisplayed : true } ) )
103+ < CanvasContainerPortal >
104+ < Canvas
105+ camera = { {
106+ position : new THREE . Vector3 ( 0 , 6 , 6 ) ,
107+ near : 0.1 ,
108+ far : 1000 ,
109+ } }
110+ shadows
111+ style = { {
112+ position : "fixed" ,
113+ top : 0 ,
114+ left : 0 ,
115+ right : 0 ,
116+ bottom : 0 ,
117+ touchAction : "none" ,
118+ opacity : readyForRender ? 1 : 0 ,
119+ } }
120+ >
121+ { state . type === "xr8" && state . xr8 && (
122+ < XR8Controls
123+ xr8 = { state . xr8 }
124+ onPoseFound = { ( ) => setState ( ( s ) => ( { ...s , poseFound : true } ) ) }
125+ onCameraFeedDisplayed = { ( ) =>
126+ setState ( ( s ) => ( { ...s , cameraFeedDisplayed : true } ) )
127+ }
128+ />
129+ ) }
130+
131+ { state . type === "webXR" && state . webXRSession && (
132+ < WebXRControls
133+ worldSize = { 8 }
134+ webXRSession = { state . webXRSession }
135+ onPoseFound = { ( ) => setState ( ( s ) => ( { ...s , poseFound : true } ) ) }
136+ onCameraFeedDisplayed = { ( ) =>
137+ setState ( ( s ) => ( { ...s , cameraFeedDisplayed : true } ) )
138+ }
139+ />
140+ ) }
141+
142+ < React . Suspense fallback = { null } >
143+ < Environment />
144+
145+ {
146+ /* preload the dice model */
147+ ! readyForGame && (
148+ < Dice
149+ position = { [ 999 , 999 , 9999 ] }
150+ scale = { [ 0.0001 , 0.0001 , 0.0001 ] }
151+ />
152+ )
135153 }
154+
155+ { readyForGame && < Game UiPortal = { uiTunnel . In } /> }
156+ </ React . Suspense >
157+
158+ < directionalLight position = { [ 10 , 8 , 6 ] } intensity = { 0 } castShadow />
159+
160+ < Ground />
161+ </ Canvas >
162+ </ CanvasContainerPortal >
163+
164+ { false && < Visualizer /> }
165+
166+ < a href = "https://github.com/platane/yAR-htzee" title = "github repository" >
167+ < button
168+ style = { {
169+ position : "absolute" ,
170+ width : "40px" ,
171+ height : "40px" ,
172+ bottom : "10px" ,
173+ right : "10px" ,
174+ pointerEvents : "auto" ,
175+ zIndex : 1 ,
176+ } }
177+ >
178+ < GithubLogo />
179+ </ button >
180+ </ a >
181+
182+ { React . createElement ( uiTunnel . Out ) }
183+
184+ { hint === "tracking" && < TrackingHint /> }
185+
186+ { ! readyForRender && (
187+ < Over >
188+ < LoadingScreen
189+ loading = { state . type !== "waiting-user-input" }
190+ onStartFlat = { startFlat }
191+ onStartWebXR = { ( webXRSupported === true && startWebXR ) || undefined }
192+ onStartXR8 = { ( xr8Supported && startXR8 ) || undefined }
136193 />
137- ) }
138-
139- < React . Suspense fallback = { null } >
140- < Environment />
141-
142- {
143- /* preload the dice model */
144- ! readyForGame && (
145- < Dice
146- position = { [ 999 , 999 , 9999 ] }
147- scale = { [ 0.0001 , 0.0001 , 0.0001 ] }
148- />
149- )
150- }
151-
152- { readyForGame && < Game UiPortal = { uiTunnel . In } /> }
153- </ React . Suspense >
154-
155- < directionalLight position = { [ 10 , 8 , 6 ] } intensity = { 0 } castShadow />
156-
157- < Ground />
158- </ Canvas >
159-
160- < OverlayPortal >
161- { false && < Visualizer /> }
162-
163- < a href = "https://github.com/platane/yAR-htzee" title = "github" >
164- < button
165- style = { {
166- position : "absolute" ,
167- width : "40px" ,
168- height : "40px" ,
169- bottom : "10px" ,
170- right : "10px" ,
171- pointerEvents : "auto" ,
172- zIndex : 1 ,
173- } }
174- >
175- < GithubLogo />
176- </ button >
177- </ a >
178-
179- { React . createElement ( uiTunnel . Out ) }
180-
181- { hint === "tracking" && < TrackingHint /> }
182-
183- { ! readyForRender && (
184- < Over >
185- < LoadingScreen
186- loading = { state . type !== "waiting-user-input" }
187- onStartFlat = { startFlat }
188- onStartWebXR = { webXRSupported && startWebXR }
189- onStartXR8 = { xr8Supported && startXR8 }
190- />
191- </ Over >
192- ) }
193- </ OverlayPortal >
194+ </ Over >
195+ ) }
194196 </ >
195197 ) ;
196198} ;
197199
198- const OverlayPortal = ( { children } : { children ?: any } ) =>
199- createPortal ( children , document . getElementById ( "overlay" ) ! ) ;
200+ const CanvasContainerPortal = ( { children } : { children ?: any } ) => {
201+ if ( typeof document === "undefined" ) return null ;
202+ return createPortal ( children , document . getElementById ( "canvas-container" ) ! ) ;
203+ } ;
200204
201205const Over = ( { children } : { children ?: any } ) => (
202206 < div
0 commit comments