Skip to content

Commit

Permalink
Merge pull request #157 from musehq/dev
Browse files Browse the repository at this point in the history
* Many Minor Fixes (#156)

* remove workshop wings, free up wasd on textinput unmount

* suppress pointer lock errors, general cleanup

* add open in oculus menu button, enter vr on clicking continue in headset

* change direction state from input space to player space, map left button to fly, fix xr movement

* mute audio on page hide, pause menu dev mode

* add .preload to useImage and useModel

* comments and small refactors

* v2.10.0
  • Loading branch information
alex-shortt authored Jan 12, 2023
2 parents 0b5332e + 96e0d34 commit 2007317
Show file tree
Hide file tree
Showing 20 changed files with 348 additions and 273 deletions.
28 changes: 28 additions & 0 deletions examples/ideas/PreloadImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState } from "react";
import { Image, useImage, useKeypress } from "spacesvr";
import { useThree } from "@react-three/fiber";

const IMAGE_URL =
"https://d1htv66kutdwsl.cloudfront.net/e7edec86-52b6-4734-9c43-ffd70bc5bef6/9d1e5c18-3fb5-4844-8b31-1a08b800976e.ktx2";

export default function PreloadImage() {
const gl = useThree((st) => st.gl);

const [mounted, setMounted] = useState(false);
useKeypress("m", () => setMounted(!mounted), [mounted]);

useImage.preload(IMAGE_URL, gl);

if (!mounted) return null;

return (
<Image
src={IMAGE_URL}
framed
frameWidth={0.75}
size={12}
rotation-y={0}
position={[-1.4, 1.5, -12]}
/>
);
}
26 changes: 0 additions & 26 deletions examples/ideas/Wings.tsx

This file was deleted.

11 changes: 8 additions & 3 deletions examples/worlds/Hub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ export default function Hub() {
>
<Analytics />
<LostWorld />
<group position-z={-1.5}>
<group position-z={-2.25}>
<Title
position-y={1.2}
position-z={-0.75}
image="https://d27rt3a60hh1lx.cloudfront.net/spacesvr/spacesvr.png"
>
welcome to spacesvr
</Title>
<group position-y={0.8}>
<Link href="/multiplayer" position-x={-2}>
<Link href="/multiplayer" position-x={-1.5} position-z={0.75}>
visit multiplayer page
</Link>
<Link href="/media" position-x={-1}>
Expand All @@ -27,7 +28,11 @@ export default function Hub() {
<Link href="/workshop" position-x={1}>
visit workshop page
</Link>
<Link href="https://github.com/musehq/spacesvr" position-x={2}>
<Link
href="https://github.com/musehq/spacesvr"
position-x={1.5}
position-z={0.75}
>
visit github
</Link>
</group>
Expand Down
18 changes: 2 additions & 16 deletions examples/worlds/Workshop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Title from "../ideas/Title";
import Link from "../ideas/Link";
import Analytics from "../ideas/Analytics";
import Bloom from "../ideas/Bloom";
import Wings from "../ideas/Wings";
import PreloadImage from "../ideas/PreloadImage";

export default function Workshop() {
const [value, setValue] = useState("hello world");
Expand Down Expand Up @@ -94,12 +94,6 @@ export default function Workshop() {
position={[-9.5, 2, 6.4]}
rotation={[0, Math.PI, 0]}
/>
<Image
src="https://d1htv66kutdwsl.cloudfront.net/e7edec86-52b6-4734-9c43-ffd70bc5bef6/9d1e5c18-3fb5-4844-8b31-1a08b800976e.ktx2"
position={[-12.5, 2, 6.4]}
rotation={[0, Math.PI, 0]}
framed
/>
<group position={[1, 0.9, -5.5]}>
<TextInput
placeholder="First Name"
Expand Down Expand Up @@ -134,15 +128,7 @@ export default function Workshop() {
/>
<Switch position={[1, -0.3, 0]} onChange={(b) => console.log(b)} />
</group>
<Image
name="outside-eddie"
src="https://d27rtd3a60hh1lx.cloudfront.net/content/muse.place/jasonmatias/EddieWave.jpg"
framed
frameWidth={0.75}
size={12}
rotation-y={0}
position={[-1.4, 1.5, -12]}
/>
<PreloadImage />
<Video
src="https://dwvo2npct47gg.cloudfront.net/videos/AWGEDVD-final.mp4"
size={4}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spacesvr",
"version": "2.9.2",
"version": "2.10.0",
"private": true,
"description": "A standardized reality for future of the 3D Web",
"keywords": [
Expand Down
17 changes: 17 additions & 0 deletions src/layers/Environment/components/MuteOnHide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect } from "react";
import { AudioContext } from "three";

export default function MuteOnHide() {
useEffect(() => {
function handleChange() {
const context = AudioContext.getContext();
if (document.hidden) context.suspend();
else context.resume();
}

document.addEventListener("visibilitychange", handleChange);
return () => document.removeEventListener("visibilitychange", handleChange);
}, []);

return null;
}
2 changes: 2 additions & 0 deletions src/layers/Environment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Props as ContainerProps } from "@react-three/fiber/dist/declarations/sr
import { XRCanvas } from "@react-three/xr";
import { defaultCanvasProps } from "./logic/canvas";
import { EnvironmentContext, useEnvironmentState } from "./logic/environment";
import MuteOnHide from "./components/MuteOnHide";
export * from "./logic/environment";

export type EnvironmentProps = {
Expand Down Expand Up @@ -38,6 +39,7 @@ export function Environment(props: EnvironmentLayerProps) {
return (
<>
<GlobalStyles />
<MuteOnHide />
<Container ref={state.containerRef}>
<EnvironmentContext.Provider value={state}>
{loadingScreen || <LoadingScreen />}
Expand Down
40 changes: 30 additions & 10 deletions src/layers/Environment/logic/environment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
createContext,
MutableRefObject,
useCallback,
useContext,
useMemo,
useRef,
Expand All @@ -9,7 +10,17 @@ import {
import { Device, DeviceState, useDevice } from "./device";
import { AudioContext } from "three";

export type MenuItem = { text: string; action: () => void };
interface MenuLink {
text: string;
link: string;
action?: never;
}
interface MenuAction {
text: string;
link?: never;
action: () => void;
}
export type MenuItem = MenuLink | MenuAction;

export type PauseEvent = (p: boolean) => void;
export type EnvironmentState = {
Expand All @@ -32,17 +43,26 @@ export const useEnvironmentState = (name: string): EnvironmentState => {
const [paused, setPausedValue] = useState(true);
const events = useMemo<PauseEvent[]>(() => [], []);

const setPaused = (p: boolean) => {
setPausedValue(p);
const [played, setPlayed] = useState(false);

// hook into paused click event to make sure global context is running
// https://github.com/mrdoob/three.js/blob/342946c8392639028da439b6dc0597e58209c696/src/audio/AudioContext.js#L9
const context = AudioContext.getContext();
if (context.state !== "running") context.resume();
const setPaused = useCallback(
(p: boolean) => {
setPausedValue(p);

// call all pause events
events.map((ev: PauseEvent) => ev.apply(null, [p]));
};
// hook into paused click event to make sure global context is running.
// https://github.com/mrdoob/three.js/blob/342946c8392639028da439b6dc0597e58209c696/src/audio/AudioContext.js#L9
// local state to only do once so we don't interfere with MuteOnHide
if (!played) {
const context = AudioContext.getContext();
if (context.state !== "running") context.resume();
setPlayed(true);
}

// call all pause events
events.map((ev: PauseEvent) => ev.apply(null, [p]));
},
[events, played]
);

const device = useDevice();

Expand Down
76 changes: 37 additions & 39 deletions src/layers/Environment/logic/menu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { MenuItem, useEnvironment } from "../logic/environment";
import { useThree } from "@react-three/fiber";
import { XRSession } from "three";
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { isMobile } from "react-device-detect";
import { isStandaloneVR } from "../../../logic/browser";

/**
* Component to register menu items to the environment.
Expand All @@ -14,15 +15,17 @@ export function RegisterMenuItems() {
const { setMenuItems } = useEnvironment();
const vrMenu = useVRMenuItem();
const fsMenu = useFsMenuItem();
const oqMenu = useOculusMenuItem();

useEffect(() => {
const arr: MenuItem[] = [];

if (vrMenu) arr.push(vrMenu);
if (fsMenu) arr.push(fsMenu);
if (oqMenu) arr.push(oqMenu);

setMenuItems(arr);
}, [vrMenu?.text, fsMenu?.text]);
}, [vrMenu?.text, fsMenu?.text, oqMenu?.text, setMenuItems]);

return null;
}
Expand All @@ -31,32 +34,10 @@ export const useVRMenuItem = (): MenuItem | undefined => {
const gl = useThree((state) => state.gl);
const { setDevice, setPaused } = useEnvironment();

// @ts-ignore
const xr = navigator.xr;

const session = useRef<XRSession>();
const [text, setText] = useState("Enter VR");
const [supported, setSupported] = useState(false);

useEffect(() => {
const isSupported = async () => {
if (!("xr" in window.navigator)) {
setSupported(false);
return;
}

const support = await xr.isSessionSupported("immersive-vr");
setSupported(support);
};

isSupported();
}, []);

if (!supported) {
return undefined;
}

const action = () => {
const action = useCallback(() => {
async function onSessionStarted(sesh: XRSession) {
sesh.addEventListener("end", onSessionEnded);
await gl.xr.setSession(sesh);
Expand All @@ -83,22 +64,37 @@ export const useVRMenuItem = (): MenuItem | undefined => {
"layers",
],
};
// @ts-ignore
const xr = navigator.xr;
xr.requestSession("immersive-vr", sessionInit).then(onSessionStarted);
} else {
session.current?.end();
}
};
}, [gl.xr, setDevice, setPaused]);

if (!isStandaloneVR()) {
return undefined;
}

return {
text,
action,
};
};

export const useOculusMenuItem = (): MenuItem | undefined => {
if (isStandaloneVR()) return;

return {
text: "Open in Meta Quest",
link: "https://www.oculus.com/open_url/?url=" + window.location.href,
};
};

export const useFsMenuItem = (): MenuItem | undefined => {
const domElement = document.body;

const getRFS = () =>
const rfs =
domElement.requestFullscreen ||
// @ts-ignore
domElement.webkitRequestFullScreen ||
Expand All @@ -109,7 +105,7 @@ export const useFsMenuItem = (): MenuItem | undefined => {
undefined;

const [isFullscreen, setIsFullscreen] = useState(false);
const [fullscreenAvailable] = useState(getRFS() !== undefined);
const [fullscreenAvailable] = useState(rfs !== undefined);

useEffect(() => {
const handleFullscreenChange = () =>
Expand All @@ -121,21 +117,23 @@ export const useFsMenuItem = (): MenuItem | undefined => {
};
}, []);

if (!fullscreenAvailable) {
const action = useCallback(() => {
if (!rfs) return;
if (!document.fullscreenElement) {
rfs.apply(domElement, [{ navigationUI: "hide" }]);
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}, [domElement, rfs]);

if (!fullscreenAvailable || isStandaloneVR()) {
return undefined;
}

return {
text: `${isFullscreen ? "Exit" : "Enter"} Fullscreen`,
action: () => {
if (!document.fullscreenElement) {
const rfs = getRFS();
rfs.apply(domElement, [{ navigationUI: "hide" }]);
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
},
action,
};
};
Loading

1 comment on commit 2007317

@vercel
Copy link

@vercel vercel bot commented on 2007317 Jan 12, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.