Skip to content

Commit d738b80

Browse files
authored
Merge pull request #135 from musehq/dev
v2.6.0
2 parents a87141c + 40c7f11 commit d738b80

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1879
-261
lines changed

README.md

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ _the following are each a fundamental unit and their own folder at the top level
9898

9999
**realities** define how the player experiences your world. They are comparable in function to a browser. They are implemented as a React container component and composed of an ordering of layers.
100100

101-
**tools** offer the player affordances in your world. They are implemented as ideas using the Tool modifier, accessed by single keystrokes.
101+
**tools** offer the player affordances in your world. They are the 3D equivalent of a browser toolbar. They are implemented using a Layer for fundamental state a modifier for registry.
102102

103103
**worlds** are sets of ideas. They are the actual content of your site. They are implemented as compositions of ideas.
104104

@@ -113,7 +113,7 @@ _the following are each a fundamental unit and their own folder at the top level
113113

114114
#### Standard Reality
115115

116-
The Standard Reality defines the standard experiencing the 3D web. The layers provided are the Environment Layer, Physics Layer, Player Layer, and Network Layer. Additionally, it provides an infinite ground to walk on that can be disabled.
116+
The Standard Reality defines the standard experiencing the 3D web. The layers provided are, in order: Environment, Physics, Player, Toolbelt, Network, Visual. Additionally, it provides an infinite ground to walk on that can be disabled.
117117

118118
```tsx
119119
<StandardReality
@@ -188,6 +188,32 @@ type PlayerState = {
188188
};
189189
```
190190

191+
#### Toolbelt Layer
192+
193+
_Provides a layer of UX to offer user interaction with the world._
194+
195+
```tsx
196+
type ToolbeltProps = {
197+
showOnSpawn?: boolean; // whether to show the toolbelt on spawn, default true
198+
};
199+
```
200+
201+
```tsx
202+
const toolbelt = useToolbelt();
203+
204+
type ToolbeltState = {
205+
tools: Tool[];
206+
activeTool?: Tool;
207+
hide: () => void;
208+
next: () => void;
209+
prev: () => void;
210+
show: () => void;
211+
activeIndex: number | undefined;
212+
setActiveIndex: (i: number) => void;
213+
direction: Direction;
214+
};
215+
```
216+
191217
#### Network Layer
192218

193219
_Provides multiplayer out-of-the-box. Muse provides signalling servers and [STUN/TURN](https://www.twilio.com/docs/stun-turn/faq#faq-what-is-nat) servers for everyone :)._
@@ -223,6 +249,22 @@ type NetworkState = {
223249
};
224250
```
225251

252+
## Tools
253+
254+
#### Camera Tool
255+
256+
A tool that gives the user a camera to take pictures with. To add to your toolbelt simply add it into the World.
257+
258+
```tsx
259+
<StandardReality>
260+
<Camera />
261+
</StandardReality>
262+
```
263+
264+
#### Walkie Talkie Tool
265+
266+
A tool to configure your microphone settings. Automatically added if voice chat is enabled in the network layer.
267+
226268
## Ideas
227269

228270
### _types of ideas_
@@ -425,6 +467,24 @@ Makes its children react to onclick and on hover methods
425467
</Interactable>
426468
```
427469

470+
#### Tool
471+
472+
Turns its children into a tool, automatically registers it with the Tool Layer.
473+
474+
```tsx
475+
<Tool
476+
name="My Tool" // name used for identification
477+
pos={[0, 0]} // where the tool should be positioned in screen space, x:[-1, 1], y:[-1, 1]
478+
face={true} // whether the tool should face the user, default true
479+
pinY={false} // whether the tool should be pinned on the screen space y so user can look up and down
480+
range={0} // how far from the cursor the tool will stay without moving left or ight, along the x screen space axis, measured in degrees
481+
orderIndex={0} // the order in which the tool should be rendered relative to other orders, default 0, sorts low to high
482+
onSwitch={(enabled: boolean) => {}} // callback for when active tool switches, passes whether the given tool is enabled
483+
>
484+
<Stuff />
485+
</Tool>
486+
```
487+
428488
#### Anchor
429489

430490
Makes its children link out to when clicked. handles leaving vr session.
@@ -443,7 +503,7 @@ Makes its children link out to when clicked. handles leaving vr session.
443503
Turns its children into a billboard, always facing the camera.
444504

445505
```tsx
446-
<FacePlayer lockX={false} lockY={false} lockZ={false} />
506+
<FacePlayer enabled={true} lockX={false} lockY={false} lockZ={false} />
447507
```
448508

449509
#### Floating
@@ -470,17 +530,16 @@ Makes its children spin
470530
<Spinning xSpeed={0} ySpeed={1} zSpeed={0} />
471531
```
472532

473-
#### Tool
533+
#### Visual Effect
474534

475-
Provides the UX for its children to become a tool, meaning it will show up in camera at all times.
535+
Adds a render pass to the Visual Layer's render pipeline. Use to add postprocessing.
476536

477537
```tsx
478-
<Tool
479-
pos={[0, 0]} // position on screen from [-1, -1] to [1, 1]
480-
face={true} // whether the tool should face the screen
481-
distance={1} // how far away to place the item. It will scale as it moves away
482-
pinY={false} // pin the tool on the y axis
483-
/>
538+
<VisualEffect
539+
index={1} // the order in which the effects are applied, sorts low to high
540+
>
541+
<unrealBloomPass args={[new Vector2(256, 256), 0.1, 0.01, 0.95]} />
542+
</VisualEffect>
484543
```
485544

486545
---
@@ -535,6 +594,18 @@ A simple button
535594
</Button>
536595
```
537596

597+
#### Key
598+
599+
A Keyboard Key that responds to the corresponding key press. Useful for tutorials.
600+
601+
```tsx
602+
<Key
603+
keyCode="a"
604+
keyPress={["a, A"]} // optional, default is keyCode, but in case there are multiple keys to look for
605+
onPressed={(evt) => console.log("Ive been pressed!")} // optional callback when key is pressed
606+
/>
607+
```
608+
538609
#### Switch
539610

540611
A boolean switch

examples/ideas/Bloom.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { VisualEffect } from "spacesvr";
2+
import { UnrealBloomPass } from "three-stdlib";
3+
import { extend, ReactThreeFiber } from "@react-three/fiber";
4+
import { useState } from "react";
5+
import { Vector2 } from "three";
6+
7+
declare global {
8+
// eslint-disable-next-line @typescript-eslint/no-namespace
9+
namespace JSX {
10+
interface IntrinsicElements {
11+
unrealBloomPass: ReactThreeFiber.Node<
12+
UnrealBloomPass,
13+
typeof UnrealBloomPass
14+
>;
15+
}
16+
}
17+
}
18+
19+
extend({ UnrealBloomPass });
20+
21+
export default function Bloom() {
22+
const [res] = useState(() => new Vector2(256, 256));
23+
24+
return (
25+
<VisualEffect index={1}>
26+
<unrealBloomPass args={[res, 0.1, 0.01, 0.95]} />
27+
</VisualEffect>
28+
);
29+
}

examples/worlds/Multiplayer/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { StandardReality, Background, Model } from "spacesvr";
1+
import { StandardReality, Background, Model, Camera } from "spacesvr";
22
import LightSwitch from "./ideas/LightSwitch";
33
import PingPongMulti from "./ideas/PingPongMulti";
44
import Title from "../../ideas/Title";
@@ -8,6 +8,7 @@ import Analytics from "../../ideas/Analytics";
88
export default function Multiplayer() {
99
return (
1010
<StandardReality
11+
environmentProps={{ dev: process.env.NODE_ENV === "development" }}
1112
playerProps={{ pos: [5, 1, 0], rot: Math.PI }}
1213
networkProps={{ autoconnect: true, voice: true }}
1314
>
@@ -28,6 +29,7 @@ export default function Multiplayer() {
2829
<meshBasicMaterial color={"purple"} />
2930
</mesh>
3031
<Model src="https://d27rt3a60hh1lx.cloudfront.net/models/Camera-1652915410/camera_02_cleaned.glb.gz" />
32+
<Camera />
3133
</StandardReality>
3234
);
3335
}

examples/worlds/Workshop.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import {
77
TextInput,
88
Switch,
99
LostWorld,
10+
Camera,
1011
} from "spacesvr";
1112
import Title from "../ideas/Title";
1213
import Link from "../ideas/Link";
1314
import Analytics from "../ideas/Analytics";
15+
import Bloom from "../ideas/Bloom";
1416

1517
export default function Workshop() {
1618
const [value, setValue] = useState("hello world");
@@ -40,7 +42,9 @@ export default function Workshop() {
4042
const [hovering, setHovering] = useState(false);
4143

4244
return (
43-
<StandardReality>
45+
<StandardReality
46+
environmentProps={{ dev: process.env.NODE_ENV === "development" }}
47+
>
4448
<Image
4549
src="https://uploads.codesandbox.io/uploads/user/b3e56831-8b98s-4fee-b941-0e27f39883ab/I9vI-RoNmD7W.png"
4650
position={[-8, 2, 6.4]}
@@ -139,6 +143,8 @@ export default function Workshop() {
139143
rotation={[0, -Math.PI, 0]}
140144
muted
141145
/>
146+
<Camera />
147+
<Bloom />
142148
</StandardReality>
143149
);
144150
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "spacesvr",
3-
"version": "2.5.4",
3+
"version": "2.6.0",
44
"private": true,
55
"description": "A standardized reality for future of the 3D Web",
66
"keywords": [

src/ideas/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@ export * from "./basis/VisualWorld";
44
export * from "./environment/Background";
55
export * from "./environment/Fog";
66
export * from "./environment/InfinitePlane";
7-
export * from "./media/Image";
87
export * from "./media/Audio";
98
export * from "./media/HDRI";
9+
export * from "./media/Image";
1010
export * from "./media/Model";
1111
export * from "./media/Video";
12-
export * from "./mediated/LostFloor";
1312
export * from "./mediated/Frame";
13+
export * from "./mediated/LostFloor";
1414
export * from "./modifiers/Collidable";
1515
export * from "./modifiers/Interactable";
16+
export * from "./modifiers/Tool";
1617
export * from "./modifiers/Anchor";
1718
export * from "./modifiers/FacePlayer";
1819
export * from "./modifiers/Floating";
1920
export * from "./modifiers/LookAtPlayer";
2021
export * from "./modifiers/Spinning";
21-
export * from "./modifiers/Tool";
22+
export * from "./modifiers/VisualEffect";
2223
export * from "./ui/TextInput";
2324
export * from "./ui/Arrow";
2425
export * from "./ui/Button";
26+
export * from "./ui/Key";
2527
export * from "./ui/Switch";

src/ideas/mediated/Frame.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export function Frame(props: FrameProps) {
127127
}, [innerFrameMaterial, width, height]);
128128

129129
return (
130-
<group name="frame">
130+
<group name="spacesvr-frame">
131131
<mesh geometry={geometry} material={material} />
132132
{backFrameGeometry && innerFrameMaterial && (
133133
<mesh geometry={backFrameGeometry} material={innerFrameMaterial} />

src/ideas/modifiers/Collidable/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export function Collidable(props: CollidableProps) {
9191
}, [collisionMeshes, hideCollisionMeshes]);
9292

9393
return (
94-
<group name="collidable" ref={group}>
94+
<group name="spacesvr-collidable" ref={group}>
9595
{children}
9696
{enabled &&
9797
collisionGeos &&

src/ideas/modifiers/FacePlayer.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
import { ReactNode, useRef } from "react";
2-
import { useFrame } from "@react-three/fiber";
3-
import { useLimiter } from "../../logic/limiter";
4-
import { Group } from "three";
1+
import { ReactNode, useRef, useState } from "react";
2+
import { useLimitedFrame } from "../../logic/limiter";
3+
import { Euler, Group } from "three";
54

65
type FacePlayerProps = {
76
children: ReactNode | ReactNode[];
7+
enabled?: boolean;
88
lockX?: boolean;
99
lockY?: boolean;
1010
lockZ?: boolean;
1111
};
1212

1313
export function FacePlayer(props: FacePlayerProps) {
14-
const { children, lockX = false, lockY = false, lockZ = false } = props;
14+
const {
15+
children,
16+
enabled = true,
17+
lockX = false,
18+
lockY = false,
19+
lockZ = false,
20+
} = props;
1521

1622
const group = useRef<Group>(null);
17-
const limiter = useLimiter(45);
23+
const [prev] = useState(new Euler());
1824

19-
useFrame(({ clock, camera }) => {
20-
if (!limiter.isReady(clock)) return;
25+
useLimitedFrame(50, ({ camera }) => {
26+
if (!group.current) return;
2127

22-
if (group.current) {
23-
const prev = {
24-
x: group.current.rotation.x,
25-
y: group.current.rotation.y,
26-
z: group.current.rotation.z,
27-
};
28+
if (!enabled) {
29+
group.current.rotation.set(0, 0, 0);
30+
} else {
31+
prev.copy(group.current.rotation);
2832
group.current.lookAt(camera.position);
2933
if (lockX) group.current.rotation.x = prev.x;
3034
if (lockY) group.current.rotation.y = prev.y;

src/ideas/modifiers/Interactable/components/MobileDesktopInteractable.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,14 @@ export default function MobileDesktopInteractable(props: InteractableProps) {
8787
}
8888
};
8989

90-
gl.domElement.addEventListener("mousedown", startPress);
91-
gl.domElement.addEventListener("mouseup", endPress);
90+
const startev = device.mobile ? "touchstart" : "mousedown";
91+
const endev = device.mobile ? "touchend" : "mouseup";
92+
gl.domElement.addEventListener(startev, startPress);
93+
gl.domElement.addEventListener(endev, endPress);
9294

9395
return () => {
94-
gl.domElement.removeEventListener("mousedown", startPress);
95-
gl.domElement.removeEventListener("mouseup", endPress);
96+
gl.domElement.removeEventListener(startev, startPress);
97+
gl.domElement.removeEventListener(endev, endPress);
9698
};
9799
}, [
98100
DETECT_HOVER,

0 commit comments

Comments
 (0)