@react-three/viverse 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,27 @@
1
1
  import { CharacterAnimationOptions, StartAnimationOptions } from '@pmndrs/viverse';
2
2
  import { RootState } from '@react-three/fiber';
3
3
  import { ActionParams } from '@react-three/timeline';
4
- import { AnimationActionLoopStyles } from 'three';
5
- export declare function CharacterAnimationAction({ until, init, dependencies, update, fadeDuration, paused, loop, ...animationOptions }: {
4
+ import { ReactNode } from 'react';
5
+ import { AnimationAction, AnimationActionLoopStyles, AnimationClip } from 'three';
6
+ export type AdditiveCharacterAnimationActionProps = Omit<CharacterAnimationActionProps, 'additiveToClip'> & {
7
+ referenceClip: CharacterAnimationOptions;
8
+ };
9
+ export declare const AdditiveCharacterAnimationAction: import("react").ForwardRefExoticComponent<Omit<CharacterAnimationActionProps, "additiveToClip"> & {
10
+ referenceClip: CharacterAnimationOptions;
11
+ } & import("react").RefAttributes<AnimationAction>>;
12
+ export type CharacterAnimationActionProps = {
6
13
  dependencies?: Array<unknown>;
7
14
  until?: () => Promise<unknown>;
8
15
  loop?: AnimationActionLoopStyles;
9
- } & Omit<ActionParams<RootState>, 'until'> & CharacterAnimationOptions & StartAnimationOptions): import("react/jsx-runtime").JSX.Element;
16
+ additiveReferenceClip?: AnimationClip;
17
+ } & Omit<ActionParams<RootState>, 'until'> & CharacterAnimationOptions & StartAnimationOptions;
18
+ export declare function CharacterAnimationLayer({ name, children }: {
19
+ name: string;
20
+ children?: ReactNode;
21
+ }): import("react/jsx-runtime").JSX.Element;
22
+ export declare const CharacterAnimationAction: import("react").ForwardRefExoticComponent<{
23
+ dependencies?: Array<unknown>;
24
+ until?: () => Promise<unknown>;
25
+ loop?: AnimationActionLoopStyles;
26
+ additiveReferenceClip?: AnimationClip;
27
+ } & Omit<ActionParams<RootState>, "until"> & CharacterAnimationOptions & StartAnimationOptions & import("react").RefAttributes<AnimationAction>>;
package/dist/animation.js CHANGED
@@ -1,18 +1,44 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { startAnimation } from '@pmndrs/viverse';
3
3
  import { Action, animationFinished } from '@react-three/timeline';
4
- import { useMemo } from 'react';
4
+ import { createContext, forwardRef, useContext, useImperativeHandle, useMemo } from 'react';
5
5
  import { LoopRepeat } from 'three';
6
+ import { makeClipAdditive } from 'three/src/animation/AnimationUtils.js';
6
7
  import { useCharacterModel } from './model.js';
7
8
  import { useCharacterAnimationLoader } from './utils.js';
8
- export function CharacterAnimationAction({ until, init, dependencies, update, fadeDuration = 0.1, paused, loop, ...animationOptions }) {
9
+ export const AdditiveCharacterAnimationAction = forwardRef(({ referenceClip: referenceClipOptions, ...props }, ref) => {
9
10
  const model = useCharacterModel();
10
- const clip = useCharacterAnimationLoader(model, animationOptions);
11
+ const referenceClip = useCharacterAnimationLoader(model, { ...props, ...referenceClipOptions });
12
+ return _jsx(CharacterAnimationAction, { ref: ref, additiveReferenceClip: referenceClip, ...props });
13
+ });
14
+ const CharacterAnimationLayerContext = createContext(undefined);
15
+ export function CharacterAnimationLayer({ name, children }) {
16
+ return _jsx(CharacterAnimationLayerContext.Provider, { value: name, children: children });
17
+ }
18
+ export const CharacterAnimationAction = forwardRef(({ additiveReferenceClip, until, init, dependencies, update, fadeDuration, paused, loop, sync, crossFade, layer, ...animationOptions }, ref) => {
19
+ const layerFromContext = useContext(CharacterAnimationLayerContext);
20
+ layer ??= layerFromContext;
21
+ const model = useCharacterModel();
22
+ const srcClip = useCharacterAnimationLoader(model, animationOptions);
23
+ const clip = useMemo(() => additiveReferenceClip == null ? srcClip : makeClipAdditive(srcClip.clone(), undefined, additiveReferenceClip), [srcClip, additiveReferenceClip]);
11
24
  const animation = useMemo(() => model.mixer.clipAction(clip), [clip, model]);
12
25
  animation.clampWhenFinished = true;
13
26
  animation.loop = loop ?? LoopRepeat;
27
+ useImperativeHandle(ref, () => animation, [animation]);
14
28
  return (_jsx(Action, { init: () => {
15
- startAnimation(animation, model.currentAnimations, { fadeDuration, paused });
16
- return init?.();
17
- }, until: until ?? (() => animationFinished(animation)), update: update, dependencies: dependencies }));
18
- }
29
+ const cleanupAnimation = startAnimation(animation, model.currentAnimations, {
30
+ layer,
31
+ fadeDuration,
32
+ paused,
33
+ sync,
34
+ crossFade,
35
+ });
36
+ const cleanupInit = init?.();
37
+ return () => {
38
+ cleanupInit?.();
39
+ cleanupAnimation?.();
40
+ };
41
+ }, until: until ?? (() => animationFinished(animation)), update: update, dependencies: dependencies != null
42
+ ? [...dependencies, animationOptions.mask, fadeDuration, paused, sync, crossFade, animation, model, layer]
43
+ : undefined }));
44
+ });
package/dist/bone.d.ts CHANGED
@@ -4,3 +4,7 @@ export declare function CharacterModelBone({ bone, children }: {
4
4
  bone: VRMHumanBoneName;
5
5
  children?: ReactNode;
6
6
  }): import("react/jsx-runtime").JSX.Element | null;
7
+ /**
8
+ * @deprecated use CharacterModelBone instead
9
+ */
10
+ export declare const VrmCharacterModelBone: typeof CharacterModelBone;
package/dist/bone.js CHANGED
@@ -12,3 +12,7 @@ export function CharacterModelBone({ bone, children }) {
12
12
  }
13
13
  return (_jsx(Fragment, { children: createPortal(_jsx("group", { quaternion: model.boneRotationOffset, children: children }), boneObject) }, boneObject.id));
14
14
  }
15
+ /**
16
+ * @deprecated use CharacterModelBone instead
17
+ */
18
+ export const VrmCharacterModelBone = CharacterModelBone;
package/dist/gamepad.d.ts CHANGED
@@ -1,2 +1 @@
1
- import { Input } from '@pmndrs/viverse';
2
- export declare function useXRControllerInput(): Input<{}>;
1
+ export declare function useXRControllerInput(): void;
package/dist/gamepad.js CHANGED
@@ -1,38 +1,27 @@
1
- import { MoveForwardField, LastTimeJumpPressedField, MoveLeftField, MoveRightField, MoveBackwardField, RunField, } from '@pmndrs/viverse';
1
+ import { JumpAction, MoveBackwardAction, MoveForwardAction, MoveLeftAction, MoveRightAction, } from '@pmndrs/viverse';
2
+ import { useFrame } from '@react-three/fiber';
2
3
  import { useXRControllerButtonEvent, useXRInputSourceState } from '@react-three/xr';
3
- import { useMemo, useRef } from 'react';
4
+ import { useEffect, useRef } from 'react';
4
5
  export function useXRControllerInput() {
5
6
  const leftController = useXRInputSourceState('controller', 'left');
6
- const lastAPressed = useRef(null);
7
7
  const rightController = useXRInputSourceState('controller', 'right');
8
- useXRControllerButtonEvent(rightController, 'a-button', (state) => state === 'pressed' && (lastAPressed.current = performance.now() / 1000));
9
- return useMemo(() => ({
10
- get(field) {
11
- switch (field) {
12
- case MoveForwardField:
13
- case MoveBackwardField: {
14
- const thumbstickYAxis = leftController?.gamepad?.['xr-standard-thumbstick']?.yAxis;
15
- if (thumbstickYAxis == null) {
16
- return undefined;
17
- }
18
- return field === MoveBackwardField
19
- ? Math.max(0, thumbstickYAxis)
20
- : Math.max(0, -thumbstickYAxis);
21
- }
22
- case MoveLeftField:
23
- case MoveRightField: {
24
- const thumbstickXAxis = leftController?.gamepad?.['xr-standard-thumbstick']?.xAxis;
25
- if (thumbstickXAxis == null) {
26
- return undefined;
27
- }
28
- return field === MoveLeftField ? Math.max(0, -thumbstickXAxis) : Math.max(0, thumbstickXAxis);
29
- }
30
- case LastTimeJumpPressedField:
31
- return lastAPressed.current;
32
- case RunField:
33
- return (leftController?.gamepad?.['xr-standard-trigger']?.state === 'pressed');
34
- }
35
- return undefined;
36
- },
37
- }), [leftController]);
8
+ useXRControllerButtonEvent(rightController, 'a-button', (state) => state === 'pressed' && JumpAction.emit());
9
+ const forwardWriterRef = useRef(undefined);
10
+ const backwardWriterRef = useRef(undefined);
11
+ const leftWriterRef = useRef(undefined);
12
+ const rightWriterRef = useRef(undefined);
13
+ useEffect(() => {
14
+ const abortController = new AbortController();
15
+ forwardWriterRef.current = MoveForwardAction.createWriter(abortController.signal);
16
+ backwardWriterRef.current = MoveBackwardAction.createWriter(abortController.signal);
17
+ leftWriterRef.current = MoveLeftAction.createWriter(abortController.signal);
18
+ rightWriterRef.current = MoveRightAction.createWriter(abortController.signal);
19
+ return () => abortController.abort();
20
+ }, [leftController]);
21
+ useFrame(() => {
22
+ forwardWriterRef.current?.write(-Math.min(0, leftController?.gamepad?.['xr-standard-thumbstick']?.yAxis ?? 0));
23
+ backwardWriterRef.current?.write(Math.max(0, leftController?.gamepad?.['xr-standard-thumbstick']?.yAxis ?? 0));
24
+ leftWriterRef.current?.write(-Math.min(0, leftController?.gamepad?.['xr-standard-thumbstick']?.xAxis ?? 0));
25
+ rightWriterRef.current?.write(Math.max(0, leftController?.gamepad?.['xr-standard-thumbstick']?.xAxis ?? 0));
26
+ });
38
27
  }
package/dist/simple.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { RunField, shouldJump, updateSimpleCharacterInputVelocity, updateSimpleCharacterRotation, } from '@pmndrs/viverse';
2
+ import { RunAction, shouldJump, updateSimpleCharacterInputVelocity, updateSimpleCharacterRotation, } from '@pmndrs/viverse';
3
+ import { IdleAnimationUrl, JumpDownAnimationUrl, JumpForwardAnimationUrl, JumpLoopAnimationUrl, JumpUpAnimationUrl, RunAnimationUrl, WalkAnimationUrl, } from '@pmndrs/viverse/src/animation/default.js';
3
4
  import { useFrame } from '@react-three/fiber';
4
5
  import { Graph, GrapthState, Parallel, RunTimeline, Switch, SwitchCase, timePassed } from '@react-three/timeline';
5
6
  import { forwardRef, Suspense, useImperativeHandle, useRef } from 'react';
@@ -8,20 +9,20 @@ import { CharacterAnimationAction } from './animation.js';
8
9
  import { useViverseActiveAvatar } from './index.js';
9
10
  import { CharacterModelProvider } from './model.js';
10
11
  import { useBvhCharacterPhysics } from './physics.js';
11
- import { useCharacterCameraBehavior, useCharacterModelLoader, useInputSystem } from './utils.js';
12
+ import { useCharacterCameraBehavior, useCharacterModelLoader, useSimpleCharacterInputs } from './utils.js';
12
13
  export const SimpleCharacter = forwardRef(({ input, inputOptions, cameraBehavior, children, movement, physics: physicsOptions, model, useViverseAvatar, animation, ...props }, ref) => {
14
+ useSimpleCharacterInputs(input, inputOptions);
13
15
  const internalRef = useRef(null);
14
- const inputSystem = useInputSystem(input, inputOptions);
15
- useCharacterCameraBehavior(internalRef, inputSystem, cameraBehavior);
16
+ useCharacterCameraBehavior(internalRef, cameraBehavior);
16
17
  const physics = useBvhCharacterPhysics(internalRef, physicsOptions);
17
18
  const lastJumpTimeRef = useRef(-Infinity);
18
- useFrame((state) => updateSimpleCharacterInputVelocity(state.camera, inputSystem, physics, movement));
19
+ useFrame((state) => updateSimpleCharacterInputVelocity(state.camera, physics, movement));
19
20
  useFrame(() => {
20
21
  if (model != false || movement?.jump === false) {
21
22
  return;
22
23
  }
23
24
  const bufferTime = movement?.jump === true ? undefined : movement?.jump?.bufferTime;
24
- if (shouldJump(physics, inputSystem, lastJumpTimeRef.current, bufferTime)) {
25
+ if (shouldJump(physics, lastJumpTimeRef.current, bufferTime)) {
25
26
  lastJumpTimeRef.current = performance.now() / 1000;
26
27
  physics.applyVelocity(
27
28
  // eslint-disable-next-line @react-three/no-new-in-loop
@@ -29,9 +30,9 @@ export const SimpleCharacter = forwardRef(({ input, inputOptions, cameraBehavior
29
30
  }
30
31
  });
31
32
  useImperativeHandle(ref, () => internalRef.current, []);
32
- return (_jsx("group", { ...props, ref: internalRef, children: model == false ? (children) : (_jsx(SimpleCharacterModel, { animation: animation, inputSystem: inputSystem, physics: physics, model: model == true ? undefined : model, movement: movement, useViverseAvatar: useViverseAvatar, children: children })) }));
33
+ return (_jsx("group", { ...props, ref: internalRef, children: model == false ? (children) : (_jsx(SimpleCharacterModel, { animation: animation, physics: physics, model: model == true ? undefined : model, movement: movement, useViverseAvatar: useViverseAvatar, children: children })) }));
33
34
  });
34
- function SimpleCharacterModel({ children, model: modelOptions, movement, physics, useViverseAvatar = true, inputSystem, animation, }) {
35
+ function SimpleCharacterModel({ children, model: modelOptions, movement, physics, useViverseAvatar = true, animation, }) {
35
36
  const avatar = useViverseActiveAvatar();
36
37
  const model = useCharacterModelLoader(avatar != null && useViverseAvatar
37
38
  ? {
@@ -44,15 +45,15 @@ function SimpleCharacterModel({ children, model: modelOptions, movement, physics
44
45
  useFrame((state, delta) => updateSimpleCharacterRotation(delta, physics, state.camera, model, animation));
45
46
  return (_jsx(_Fragment, { children: _jsxs(CharacterModelProvider, { model: model, children: [_jsx(RunTimeline, { children: _jsxs(Graph, { enterState: "move", children: [_jsx(GrapthState, { name: "move", transitionTo: {
46
47
  jumpStart: {
47
- whenUpdate: () => shouldJump(physics, inputSystem, lastJumpTimeRef.current),
48
+ whenUpdate: () => shouldJump(physics, lastJumpTimeRef.current),
48
49
  },
49
50
  jumpLoop: { whenUpdate: () => !physics.isGrounded },
50
- }, children: _jsxs(Switch, { children: [_jsx(SwitchCase, { index: 0, condition: () => physics.inputVelocity.lengthSq() === 0, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: { default: 'idle' } }) }) }), movement?.run != false && (_jsx(SwitchCase, { index: 1, condition: () => inputSystem.get(RunField), children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.run, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.8, url: { default: 'run' } }) }) })), movement?.walk != false && (_jsx(SwitchCase, { index: 2, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.walk, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.5, url: { default: 'walk' } }) }) })), _jsx(SwitchCase, { index: 3, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: { default: 'idle' } }) }) })] }) }), _jsx(GrapthState, { name: "jumpStart", transitionTo: {
51
+ }, children: _jsxs(Switch, { children: [_jsx(SwitchCase, { index: 0, condition: () => physics.inputVelocity.lengthSq() === 0, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: IdleAnimationUrl }) }) }), movement?.run != false && (_jsx(SwitchCase, { index: 1, condition: () => RunAction.get(), children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.run, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.8, url: RunAnimationUrl }) }) })), movement?.walk != false && (_jsx(SwitchCase, { index: 2, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.walk, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.5, url: WalkAnimationUrl }) }) })), _jsx(SwitchCase, { index: 3, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.idle, fadeDuration: animation?.crossFadeDuration, url: IdleAnimationUrl }) }) })] }) }), _jsx(GrapthState, { name: "jumpStart", transitionTo: {
51
52
  jumpDown: { whenUpdate: () => !physics.isGrounded },
52
- finally: () => (inputSystem.get(RunField) ? 'jumpForward' : 'jumpUp'),
53
- }, children: _jsx(Parallel, { type: "race", children: _jsxs(Suspense, { fallback: null, children: [_jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration ?? 0.1, until: () => timePassed(0.2, 'seconds'), update: () => void physics.inputVelocity.multiplyScalar(0.3), paused: true, url: { default: 'jumpUp' } }), _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration ?? 0.1, paused: true, url: { default: 'jumpForward' } })] }) }) }), _jsx(GrapthState, { name: "jumpLoop", transitionTo: {
53
+ finally: () => (RunAction.get() ? 'jumpForward' : 'jumpUp'),
54
+ }, children: _jsx(Parallel, { type: "race", children: _jsxs(Suspense, { fallback: null, children: [_jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration ?? 0.1, until: () => timePassed(0.2, 'seconds'), update: () => void physics.inputVelocity.multiplyScalar(0.3), paused: true, url: JumpUpAnimationUrl }), _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration ?? 0.1, paused: true, url: JumpForwardAnimationUrl })] }) }) }), _jsx(GrapthState, { name: "jumpLoop", transitionTo: {
54
55
  jumpDown: { whenUpdate: () => physics.isGrounded },
55
- }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpLoop, fadeDuration: animation?.crossFadeDuration, url: { default: 'jumpLoop' } }) }) }), _jsx(GrapthState, { name: "jumpUp", transitionTo: {
56
+ }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpLoop, fadeDuration: animation?.crossFadeDuration, url: JumpLoopAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpUp", transitionTo: {
56
57
  jumpDown: {
57
58
  whenUpdate: (_, _clock, actionTime) => actionTime > 0.3 && physics.isGrounded,
58
59
  },
@@ -60,8 +61,8 @@ function SimpleCharacterModel({ children, model: modelOptions, movement, physics
60
61
  }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpUp, fadeDuration: animation?.crossFadeDuration, loop: LoopOnce, init: () => {
61
62
  lastJumpTimeRef.current = performance.now() / 1000;
62
63
  physics.applyVelocity(new Vector3(0, (typeof movement?.jump === 'object' ? movement?.jump.speed : undefined) ?? 8, 0));
63
- }, url: { default: 'jumpUp' } }) }) }), _jsx(GrapthState, { name: "jumpForward", transitionTo: { finally: () => (physics.isGrounded ? 'move' : 'jumpLoop') }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.9, init: () => {
64
+ }, url: JumpUpAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpForward", transitionTo: { finally: () => (physics.isGrounded ? 'move' : 'jumpLoop') }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpForward, fadeDuration: animation?.crossFadeDuration, scaleTime: 0.9, init: () => {
64
65
  lastJumpTimeRef.current = performance.now() / 1000;
65
66
  physics.applyVelocity(new Vector3(0, 8, 0));
66
- }, loop: LoopOnce, url: { default: 'jumpForward' } }) }) }), _jsx(GrapthState, { name: "jumpDown", transitionTo: { finally: 'move' }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpDown, fadeDuration: animation?.crossFadeDuration, until: () => timePassed(150, 'milliseconds'), loop: LoopOnce, url: { default: 'jumpDown' } }) }) })] }) }), _jsx("primitive", { object: model.scene }), children] }) }));
67
+ }, loop: LoopOnce, url: JumpForwardAnimationUrl }) }) }), _jsx(GrapthState, { name: "jumpDown", transitionTo: { finally: 'move' }, children: _jsx(Suspense, { fallback: null, children: _jsx(CharacterAnimationAction, { ...animation?.jumpDown, fadeDuration: animation?.crossFadeDuration, until: () => timePassed(150, 'milliseconds'), loop: LoopOnce, url: JumpDownAnimationUrl }) }) })] }) }), _jsx("primitive", { object: model.scene }), children] }) }));
67
68
  }
package/dist/utils.d.ts CHANGED
@@ -1,9 +1,14 @@
1
- import { CharacterAnimationOptions, CharacterModelOptions, InputSystem, SimpleCharacterCameraBehaviorOptions, CharacterModel, Input } from '@pmndrs/viverse';
1
+ import { CharacterCameraBehavior, CharacterAnimationOptions, CharacterModelOptions, SimpleCharacterCameraBehaviorOptions, CharacterModel, SimpleCharacterInputOptions } from '@pmndrs/viverse';
2
2
  import { RefObject } from 'react';
3
3
  import { Object3D } from 'three';
4
- export declare function useCharacterCameraBehavior(model: Object3D | RefObject<Object3D | null>, inputSystem: InputSystem, options?: SimpleCharacterCameraBehaviorOptions): void;
4
+ export declare function useCharacterCameraBehavior(model: Object3D | RefObject<Object3D | null>, options?: SimpleCharacterCameraBehaviorOptions): RefObject<CharacterCameraBehavior | undefined>;
5
5
  export declare function useCharacterModelLoader(options?: CharacterModelOptions): CharacterModel;
6
6
  export declare function useCharacterAnimationLoader(model: CharacterModel, options: CharacterAnimationOptions): import("three").AnimationClip;
7
- export declare function useInputSystem<T extends object>(inputs?: ReadonlyArray<Input<T> | {
8
- new (domElement: HTMLElement): Input<T>;
9
- }>, options?: T): InputSystem<T>;
7
+ /**
8
+ * @deprecated use inputs directly
9
+ */
10
+ export declare function useSimpleCharacterInputs(inputsClasses?: ReadonlyArray<{
11
+ new (domElement: HTMLElement): {
12
+ dispose(): void;
13
+ };
14
+ }>, options?: SimpleCharacterInputOptions): void;
package/dist/utils.js CHANGED
@@ -1,12 +1,20 @@
1
1
  import { VRM } from '@pixiv/three-vrm';
2
- import { CharacterCameraBehavior, flattenCharacterAnimationOptions, flattenCharacterModelOptions, InputSystem, loadCharacterModel, loadCharacterAnimation, ScreenJoystickInput, ScreenJumpButtonInput, PointerCaptureInput, LocomotionKeyboardInput, } from '@pmndrs/viverse';
2
+ import { CharacterCameraBehavior, flattenCharacterAnimationOptions, flattenCharacterModelOptions, loadCharacterModel, loadCharacterAnimation, ScreenJoystickInput, ScreenJumpButtonInput, PointerCaptureInput, LocomotionKeyboardInput, applySimpleCharacterInputOptions, } from '@pmndrs/viverse';
3
3
  import { useFrame, useThree } from '@react-three/fiber';
4
- import { useEffect, useMemo } from 'react';
4
+ import { useEffect, useMemo, useRef } from 'react';
5
5
  import { suspend } from 'suspend-react';
6
6
  import { Object3D } from 'three';
7
7
  import { useBvhPhysicsWorld } from './physics.js';
8
- export function useCharacterCameraBehavior(model, inputSystem, options) {
9
- const behavior = useMemo(() => new CharacterCameraBehavior(), []);
8
+ export function useCharacterCameraBehavior(model, options) {
9
+ const behaviorRef = useRef(undefined);
10
+ useEffect(() => {
11
+ const behavior = new CharacterCameraBehavior();
12
+ behaviorRef.current = behavior;
13
+ return () => {
14
+ behaviorRef.current = undefined;
15
+ behavior.dispose();
16
+ };
17
+ }, []);
10
18
  const world = useBvhPhysicsWorld();
11
19
  const raycast = useMemo(() => world.raycast.bind(world), [world]);
12
20
  useFrame((state, delta) => {
@@ -14,8 +22,9 @@ export function useCharacterCameraBehavior(model, inputSystem, options) {
14
22
  if (resolvedModel == null) {
15
23
  return;
16
24
  }
17
- behavior.update(state.camera, resolvedModel, inputSystem, delta, raycast, options);
25
+ behaviorRef.current?.update(state.camera, resolvedModel, delta, raycast, options);
18
26
  });
27
+ return behaviorRef;
19
28
  }
20
29
  const loadCharacterModelSymbol = Symbol('loadCharacterModel');
21
30
  export function useCharacterModelLoader(options) {
@@ -32,36 +41,39 @@ const loadCharacterAnimationSymbol = Symbol('loadCharacterAnimation');
32
41
  export function useCharacterAnimationLoader(model, options) {
33
42
  return suspend((_, ...params) => loadCharacterAnimation(...params), [loadCharacterAnimationSymbol, model, ...flattenCharacterAnimationOptions(options)]);
34
43
  }
35
- export function useInputSystem(inputs = [
44
+ /**
45
+ * @deprecated use inputs directly
46
+ */
47
+ export function useSimpleCharacterInputs(inputsClasses = [
36
48
  ScreenJoystickInput,
37
49
  ScreenJumpButtonInput,
38
50
  PointerCaptureInput,
39
51
  LocomotionKeyboardInput,
40
- ], options = {}) {
52
+ ], options) {
41
53
  const dom = useThree((s) => s.gl.domElement);
42
- const optionsRef = useMemo(() => ({}), []);
43
- //clearing and copying the options to optionsRef
44
- for (const key in optionsRef) {
45
- delete optionsRef[key];
46
- }
47
- Object.assign(optionsRef, options);
48
54
  // eslint-disable-next-line react-hooks/exhaustive-deps
49
- const system = useMemo(() => new InputSystem(optionsRef), []);
55
+ const inputs = useMemo(() => [], [dom]);
50
56
  useEffect(() => {
51
- const removedInputs = new Set(system.inputs);
52
- for (const input of inputs) {
53
- const existingInput = system.inputs.find((existingInput) => typeof input === 'function' ? existingInput instanceof input.constructor : existingInput === input);
57
+ const removedInputs = new Set(inputs);
58
+ for (const inputClass of inputsClasses) {
59
+ const existingInput = inputs.find((existingInput) => existingInput instanceof inputClass);
54
60
  if (existingInput != null) {
55
61
  removedInputs.delete(existingInput);
56
62
  continue;
57
63
  }
58
- system.add(typeof input === 'function' ? new input(dom) : input);
64
+ inputs.push(new inputClass(dom));
59
65
  }
60
66
  for (const removedInput of removedInputs) {
61
- system.remove(removedInput);
62
- removedInput.dispose?.();
67
+ removedInput.dispose();
68
+ const index = inputs.indexOf(removedInput);
69
+ if (index != -1) {
70
+ inputs.splice(index, 1);
71
+ }
63
72
  }
73
+ applySimpleCharacterInputOptions(inputs, options);
64
74
  });
65
- useEffect(() => () => system.inputs.forEach((input) => input.dispose?.()), [system]);
66
- return system;
75
+ useEffect(() => () => {
76
+ inputs.forEach((input) => input.dispose());
77
+ inputs.length = 0;
78
+ }, [inputs]);
67
79
  }
package/package.json CHANGED
@@ -24,12 +24,12 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@viverse/sdk": "^1.2.10-alpha.0",
27
- "@react-three/timeline": "^0.3.5",
27
+ "@react-three/timeline": "^0.3.7",
28
28
  "suspend-react": "^0.1.3",
29
29
  "@pixiv/three-vrm": "^3.4.2",
30
30
  "zustand": "^5.0.6",
31
31
  "@react-three/xr": "^6.6.20",
32
- "@pmndrs/viverse": "^0.2.0"
32
+ "@pmndrs/viverse": "^0.2.1"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@react-three/fiber": "*"
@@ -40,7 +40,7 @@
40
40
  "@types/react": "^19.1.8",
41
41
  "react": "^19.1.0"
42
42
  },
43
- "version": "0.2.0",
43
+ "version": "0.2.1",
44
44
  "scripts": {
45
45
  "build": "tsc",
46
46
  "check:prettier": "prettier --check src",