@ankhorage/zora-game 0.6.2 → 0.7.0
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.
- package/CHANGELOG.md +7 -0
- package/README.md +1 -2
- package/dist/ZORA_GAME_COMPONENT_META.d.ts +212 -0
- package/dist/ZORA_GAME_COMPONENT_META.d.ts.map +1 -1
- package/dist/ZORA_GAME_PLUGIN.d.ts +212 -0
- package/dist/ZORA_GAME_PLUGIN.d.ts.map +1 -1
- package/dist/ZORA_PLUGIN_METADATA.d.ts +212 -0
- package/dist/ZORA_PLUGIN_METADATA.d.ts.map +1 -1
- package/dist/features/game-presentation/adapters/inbound/GameEntity.d.ts +1 -1
- package/dist/features/game-presentation/adapters/inbound/GameEntity.d.ts.map +1 -1
- package/dist/features/game-presentation/adapters/inbound/GameEntity.js +15 -28
- package/dist/features/game-presentation/adapters/inbound/GameEntity.js.map +1 -1
- package/dist/features/game-presentation/meta/gameEntityMeta.d.ts +212 -0
- package/dist/features/game-presentation/meta/gameEntityMeta.d.ts.map +1 -1
- package/dist/features/game-presentation/meta/gameEntityMeta.js +114 -0
- package/dist/features/game-presentation/meta/gameEntityMeta.js.map +1 -1
- package/dist/features/game-presentation/public.d.ts +1 -1
- package/dist/features/game-presentation/public.d.ts.map +1 -1
- package/dist/features/game-presentation/public.js.map +1 -1
- package/dist/features/game-presentation/utils/resolveGameEntityMotionPlan.d.ts +15 -0
- package/dist/features/game-presentation/utils/resolveGameEntityMotionPlan.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/resolveGameEntityMotionPlan.js +31 -0
- package/dist/features/game-presentation/utils/resolveGameEntityMotionPlan.js.map +1 -0
- package/dist/features/game-presentation/utils/useAnimatedGameEntityValue.d.ts +5 -0
- package/dist/features/game-presentation/utils/useAnimatedGameEntityValue.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/useAnimatedGameEntityValue.js +33 -0
- package/dist/features/game-presentation/utils/useAnimatedGameEntityValue.js.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityAnimatedStyle.d.ts +16 -0
- package/dist/features/game-presentation/utils/useGameEntityAnimatedStyle.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityAnimatedStyle.js +52 -0
- package/dist/features/game-presentation/utils/useGameEntityAnimatedStyle.js.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityMeasurement.d.ts +5 -0
- package/dist/features/game-presentation/utils/useGameEntityMeasurement.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityMeasurement.js +14 -0
- package/dist/features/game-presentation/utils/useGameEntityMeasurement.js.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityMotionProgress.d.ts +5 -0
- package/dist/features/game-presentation/utils/useGameEntityMotionProgress.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/useGameEntityMotionProgress.js +87 -0
- package/dist/features/game-presentation/utils/useGameEntityMotionProgress.js.map +1 -0
- package/dist/features/game-presentation/utils/useGameReducedMotion.d.ts +3 -0
- package/dist/features/game-presentation/utils/useGameReducedMotion.d.ts.map +1 -0
- package/dist/features/game-presentation/utils/useGameReducedMotion.js +13 -0
- package/dist/features/game-presentation/utils/useGameReducedMotion.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/gamePresentation.d.ts +18 -1
- package/dist/types/gamePresentation.d.ts.map +1 -1
- package/dist/types/gamePresentation.js.map +1 -1
- package/package.json +1 -1
- package/src/ZORA_PLUGIN_METADATA.test.ts +17 -0
- package/src/features/game-presentation/adapters/inbound/GameEntity.tsx +19 -69
- package/src/features/game-presentation/meta/gameEntityMeta.ts +115 -0
- package/src/features/game-presentation/public.ts +2 -0
- package/src/features/game-presentation/utils/resolveGameEntityMotionPlan.test.ts +63 -0
- package/src/features/game-presentation/utils/resolveGameEntityMotionPlan.ts +53 -0
- package/src/features/game-presentation/utils/useAnimatedGameEntityValue.ts +41 -0
- package/src/features/game-presentation/utils/useGameEntityAnimatedStyle.ts +87 -0
- package/src/features/game-presentation/utils/useGameEntityMeasurement.ts +19 -0
- package/src/features/game-presentation/utils/useGameEntityMotionProgress.ts +114 -0
- package/src/features/game-presentation/utils/useGameReducedMotion.ts +15 -0
- package/src/index.ts +2 -0
- package/src/types/gamePresentation.ts +19 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Animated, Easing } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { GameEntityEasing } from '../../../types/gamePresentation';
|
|
5
|
+
import type { GameEntityMotionPlan } from './resolveGameEntityMotionPlan';
|
|
6
|
+
|
|
7
|
+
interface MotionAnimationInput {
|
|
8
|
+
readonly durationMs: number;
|
|
9
|
+
readonly delayMs: number;
|
|
10
|
+
readonly easing: GameEntityEasing;
|
|
11
|
+
readonly repeat: boolean;
|
|
12
|
+
readonly alternate: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/*** Drive one optional relative GameEntity motion timeline without changing game-session state. */
|
|
16
|
+
export function useGameEntityMotionProgress(plan: GameEntityMotionPlan): Animated.Value {
|
|
17
|
+
const [progress] = React.useState(() => new Animated.Value(0));
|
|
18
|
+
const signature = createMotionSignature(plan);
|
|
19
|
+
const previousSignature = React.useRef(signature);
|
|
20
|
+
const {
|
|
21
|
+
motionEnabled,
|
|
22
|
+
motionPaused,
|
|
23
|
+
motionDurationMs,
|
|
24
|
+
motionDelayMs,
|
|
25
|
+
motionEasing,
|
|
26
|
+
motionRepeat,
|
|
27
|
+
motionAlternate,
|
|
28
|
+
} = plan;
|
|
29
|
+
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
progress.stopAnimation();
|
|
32
|
+
|
|
33
|
+
if (!motionEnabled) {
|
|
34
|
+
progress.setValue(0);
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (previousSignature.current !== signature) {
|
|
39
|
+
progress.setValue(0);
|
|
40
|
+
previousSignature.current = signature;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (motionPaused) return undefined;
|
|
44
|
+
|
|
45
|
+
const animation = createMotionAnimation(progress, {
|
|
46
|
+
durationMs: motionDurationMs,
|
|
47
|
+
delayMs: motionDelayMs,
|
|
48
|
+
easing: motionEasing,
|
|
49
|
+
repeat: motionRepeat,
|
|
50
|
+
alternate: motionAlternate,
|
|
51
|
+
});
|
|
52
|
+
animation.start();
|
|
53
|
+
return () => animation.stop();
|
|
54
|
+
}, [
|
|
55
|
+
motionAlternate,
|
|
56
|
+
motionDelayMs,
|
|
57
|
+
motionDurationMs,
|
|
58
|
+
motionEasing,
|
|
59
|
+
motionEnabled,
|
|
60
|
+
motionPaused,
|
|
61
|
+
motionRepeat,
|
|
62
|
+
progress,
|
|
63
|
+
signature,
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
return progress;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*** Create the one-shot or repeating React Native motion sequence for one entity. */
|
|
70
|
+
function createMotionAnimation(progress: Animated.Value, input: MotionAnimationInput) {
|
|
71
|
+
const forward = () =>
|
|
72
|
+
Animated.timing(progress, {
|
|
73
|
+
toValue: 1,
|
|
74
|
+
duration: input.durationMs,
|
|
75
|
+
easing: resolveMotionEasing(input.easing),
|
|
76
|
+
useNativeDriver: false,
|
|
77
|
+
});
|
|
78
|
+
const reverse = () =>
|
|
79
|
+
Animated.timing(progress, {
|
|
80
|
+
toValue: 0,
|
|
81
|
+
duration: input.durationMs,
|
|
82
|
+
easing: resolveMotionEasing(input.easing),
|
|
83
|
+
useNativeDriver: false,
|
|
84
|
+
});
|
|
85
|
+
const movement = input.alternate
|
|
86
|
+
? Animated.loop(Animated.sequence([forward(), reverse()]))
|
|
87
|
+
: input.repeat
|
|
88
|
+
? Animated.loop(forward())
|
|
89
|
+
: forward();
|
|
90
|
+
|
|
91
|
+
return input.delayMs === 0
|
|
92
|
+
? movement
|
|
93
|
+
: Animated.sequence([Animated.delay(input.delayMs), movement]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/*** Create a stable signature for motion parameters that should restart the relative timeline. */
|
|
97
|
+
function createMotionSignature(plan: GameEntityMotionPlan): string {
|
|
98
|
+
return [
|
|
99
|
+
plan.motionDurationMs,
|
|
100
|
+
plan.motionDelayMs,
|
|
101
|
+
plan.motionEasing,
|
|
102
|
+
plan.motionEnabled,
|
|
103
|
+
plan.motionRepeat,
|
|
104
|
+
plan.motionAlternate,
|
|
105
|
+
].join(':');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/*** Map serializable timeline easing names onto React Native easing functions. */
|
|
109
|
+
function resolveMotionEasing(easing: GameEntityEasing) {
|
|
110
|
+
if (easing === 'ease-in') return Easing.in(Easing.ease);
|
|
111
|
+
if (easing === 'ease-out') return Easing.out(Easing.ease);
|
|
112
|
+
if (easing === 'ease-in-out') return Easing.inOut(Easing.ease);
|
|
113
|
+
return Easing.linear;
|
|
114
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AccessibilityInfo } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/*** Track the cross-platform system reduced-motion preference for game presentation. */
|
|
5
|
+
export function useGameReducedMotion(): boolean {
|
|
6
|
+
const [reduceMotion, setReduceMotion] = React.useState(false);
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
void AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
|
|
10
|
+
const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduceMotion);
|
|
11
|
+
return () => subscription.remove();
|
|
12
|
+
}, []);
|
|
13
|
+
|
|
14
|
+
return reduceMotion;
|
|
15
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,24 @@ import type React from 'react';
|
|
|
4
4
|
type GameOverlayCornerPlacement = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
5
5
|
|
|
6
6
|
export type GamePointerEvents = 'auto' | 'box-none' | 'box-only' | 'none';
|
|
7
|
+
export type GameEntityEasing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
8
|
+
|
|
9
|
+
export interface GameEntityMotionProps {
|
|
10
|
+
readonly transitionDurationMs?: number;
|
|
11
|
+
readonly transitionEasing?: GameEntityEasing;
|
|
12
|
+
readonly motionOffsetX?: number;
|
|
13
|
+
readonly motionOffsetY?: number;
|
|
14
|
+
readonly motionOpacityDelta?: number;
|
|
15
|
+
readonly motionScaleDelta?: number;
|
|
16
|
+
readonly motionRotationDelta?: number;
|
|
17
|
+
readonly motionDurationMs?: number;
|
|
18
|
+
readonly motionDelayMs?: number;
|
|
19
|
+
readonly motionEasing?: GameEntityEasing;
|
|
20
|
+
readonly motionRepeat?: boolean;
|
|
21
|
+
readonly motionAlternate?: boolean;
|
|
22
|
+
readonly motionPaused?: boolean;
|
|
23
|
+
readonly motionEssential?: boolean;
|
|
24
|
+
}
|
|
7
25
|
export type GameOverlayPlacement =
|
|
8
26
|
'fill' | 'center' | 'top' | 'bottom' | GameOverlayCornerPlacement;
|
|
9
27
|
|
|
@@ -16,7 +34,7 @@ export interface GameFieldProps {
|
|
|
16
34
|
readonly testID?: string;
|
|
17
35
|
}
|
|
18
36
|
|
|
19
|
-
export interface GameEntityProps {
|
|
37
|
+
export interface GameEntityProps extends GameEntityMotionProps {
|
|
20
38
|
readonly children?: React.ReactNode;
|
|
21
39
|
readonly x?: number;
|
|
22
40
|
readonly y?: number;
|