Skip to main content

Interaction with @coconut-xr/koestlich

Creating a koestlich UI

Building a UI in WebXR can be achieved with koestlich. natuerlich provides out-of-the-box support for interaction with koestlich, such as scrolling.

The following example creates a simple UI with koestlich that changes its background color when clicked using a TouchHand and TouchController.

info

For more information on how to build 3D UIs visit the koestlich documentation.

import {
XRCanvas,
PointerHand,
PointerController
} from "@coconut-xr/natuerlich/defaults";
import { RootText } from "@coconut-xr/koestlich";
import { getInputSourceId } from "@coconut-xr/natuerlich";
import {
useEnterXR,
NonImmersiveCamera,
ImmersiveSessionOrigin
} from "@coconut-xr/natuerlich/react";
import { useState } from "react";

const sessionOptions: XRSessionInit = {
requiredFeatures: ["local-floor", "hand-tracking"]
};

export default function Index() {
const enterAR = useEnterXR("immersive-ar", sessionOptions);
const [blue, setBlue] = useState(false);

return (
<div
style={{...}}
>
<button onClick={enterAR}>Enter AR</button>
<XRCanvas>
<group position={[0, 1.5, 1]}>
<RootText
onClick={() => setBlue((blue) => !blue)}
anchorX="center"
anchorY="center"
padding={0.05}
backgroundColor={blue ? "blue" : "green"}
>
Hello World
</RootText>
</group>
<NonImmersiveCamera position={[0, 1.5, 4]} />
<ImmersiveSessionOrigin position={[0, 0, 4]}>
<Hands type="pointer" />
<Controllers type="grab" />
</ImmersiveSessionOrigin>
</XRCanvas>
</div>
);
}

Binding a koestlich UI to the Hand / Controller

Binding an interactive UI to the hands of the users can feel very intuitive. The following example shows how a Koestlich UI can be bound to the wrist. The example requires to create and use custom hands. Therefore, we recommend to read the Input Sources documentation first.

import {
XRCanvas,
PointerHand,
PointerController
} from "@coconut-xr/natuerlich/defaults";
import { RootText } from "@coconut-xr/koestlich";
import { getInputSourceId } from "@coconut-xr/natuerlich";
import {
useEnterXR,
NonImmersiveCamera,
ImmersiveSessionOrigin,
useInputSources
} from "@coconut-xr/natuerlich/react";
import { useState } from "react";

const sessionOptions: XRSessionInit = {
requiredFeatures: ["local-floor", "hand-tracking"]
};

function UI() {
const [blue, setBlue] = useState(false);
return (
<RootText
onClick={() => setBlue((blue) => !blue)}
anchorX="center"
anchorY="center"
padding={0.05}
backgroundColor={blue ? "blue" : "green"}
>
Hello World
</RootText>
);
}

export default function Index() {
const enterAR = useEnterXR("immersive-ar", sessionOptions);
const inputSources = useInputSources();

return (
<div
style={{
position: "absolute",
inset: 0,
display: "flex",
flexDirection: "column"
}}
>
<button onClick={enterAR}>Enter AR</button>
<XRCanvas>
<NonImmersiveCamera position={[0, 1.5, 4]} />
<ImmersiveSessionOrigin position={[0, 0, 4]}>
{inputSources.map((inputSource) =>
inputSource.hand != null ? (
<PointerHand
id={getInputSourceId(inputSource)}
key={getInputSourceId(inputSource)}
inputSource={inputSource}
hand={inputSource.hand}
childrenAtJoint="wrist"
>
<UI />
</PointerHand>
) : (
<PointerController
id={getInputSourceId(inputSource)}
key={getInputSourceId(inputSource)}
inputSource={inputSource}
>
<UI />
</PointerController>
)
)}
</ImmersiveSessionOrigin>
</XRCanvas>
</div>
);
}

Question not answered?

If your questions were not yet answered, visit our Discord 😉