create-proto 0.3.1 → 0.4.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/package.json +2 -2
- package/template/CLAUDE.md +10 -0
- package/template/assets/lottie/.gitkeep +0 -0
- package/template/components/proto/canvas/index.ts +15 -0
- package/template/components/proto/gestures/index.ts +21 -0
- package/template/components/proto/lottie/index.tsx +13 -0
- package/template/components/proto/motion/index.tsx +80 -0
- package/template/package.json +3 -0
- package/template/pnpm-workspace.yaml +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-proto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Scaffold a new Proto prototype: `npm create proto@latest myapp`. Designer-first native iOS prototyping environment that pairs with Claude Code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@clack/prompts": "^0.7.0",
|
|
45
|
-
"@sherizan/proto-cli": "^0.
|
|
45
|
+
"@sherizan/proto-cli": "^0.4.0",
|
|
46
46
|
"fs-extra": "^11.2.0",
|
|
47
47
|
"qrcode-terminal": "^0.12.0",
|
|
48
48
|
"validate-npm-package-name": "^5.0.1"
|
package/template/CLAUDE.md
CHANGED
|
@@ -18,6 +18,15 @@ You're the design tool inside a Prototo project. The designer prompts you in pla
|
|
|
18
18
|
|
|
19
19
|
**Prototo primitives** in `/components/proto` — small set of themed fallbacks: `Screen`, `Stack`, `Row`, `Text`, `Card`, `Button`, `Toggle`, `Divider`, `Modal`. Read the file when you need the API. Card's `glass={true}` uses `expo-glass-effect`'s native iOS 26 material; on older iOS it falls back to a plain View.
|
|
20
20
|
|
|
21
|
+
**Prototo motion + graphics** — four subpath modules in `/components/proto` cover animation and drawing. Pick by what the prompt actually asks for:
|
|
22
|
+
|
|
23
|
+
- `../components/proto/motion` — `Motion.View` + `Motion.Pressable`. **Default for transitions.** Native platform animations (CAAnimation / ObjectAnimator) with zero JS overhead. Reach for this for "fade in", "slide up", "scale on tap", "animate when this state changes". Driven by `react-native-ease`.
|
|
24
|
+
- `../components/proto/gestures` — `AnimatedView`, `useSharedValue`, `useAnimatedStyle`, `withSpring`, `Gesture`, `GestureDetector`, etc. Use **only** when the animation must read gesture state, scroll position, or interpolate continuously: "drag this card", "swipe to delete", "parallax this header". Driven by `react-native-reanimated` + `react-native-gesture-handler`.
|
|
25
|
+
- `../components/proto/lottie` — `Lottie` component. Plays `.json` files dropped into `/assets/lottie/`. The designer brings the animation file (LottieFiles / After Effects export); you wire it: `<Lottie source={require('../assets/lottie/<name>.json')} />`. Defaults to `autoPlay` and `loop`. Driven by `lottie-react-native`.
|
|
26
|
+
- `../components/proto/canvas` — `Canvas`, `Path`, `Circle`, `Rect`, `LinearGradient`, etc. For custom drawing that doesn't fit RN's box model: confetti bursts, custom charts, badge shapes. Driven by `@shopify/react-native-skia`.
|
|
27
|
+
|
|
28
|
+
Never import `react-native-ease`, `react-native-reanimated`, `lottie-react-native`, or `@shopify/react-native-skia` directly in a screen — always route through the `../components/proto/<subpath>` module above. If `motion` can't express what's needed, fall back to `gestures`.
|
|
29
|
+
|
|
21
30
|
**Share** — `proto share` starts a tunnel + registers a `prototo.app/p/<token>` link. Stakeholders open the link on iPhone with Prototo App to view the live prototype.
|
|
22
31
|
|
|
23
32
|
**Custom** — when none of the above fit, write the component you need with React Native. Put shared ones in `/components/shared/`. The designer's vision wins; primitives are starting points, not constraints.
|
|
@@ -30,6 +39,7 @@ You're the design tool inside a Prototo project. The designer prompts you in pla
|
|
|
30
39
|
/screens/<Name>.tsx screen, PascalCase, default export
|
|
31
40
|
/components/shared/ designer-created custom components
|
|
32
41
|
/components/proto/ Prototo primitives — read-only
|
|
42
|
+
/assets/lottie/ designer-supplied Lottie JSON files (loaded by the Lottie component)
|
|
33
43
|
```
|
|
34
44
|
|
|
35
45
|
A new screen `screens/Settings.tsx` needs:
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export {
|
|
2
|
+
default as AnimatedView,
|
|
3
|
+
useSharedValue,
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
useDerivedValue,
|
|
6
|
+
useAnimatedScrollHandler,
|
|
7
|
+
useAnimatedReaction,
|
|
8
|
+
withTiming,
|
|
9
|
+
withSpring,
|
|
10
|
+
withDelay,
|
|
11
|
+
withSequence,
|
|
12
|
+
withRepeat,
|
|
13
|
+
cancelAnimation,
|
|
14
|
+
interpolate,
|
|
15
|
+
Extrapolation,
|
|
16
|
+
Easing,
|
|
17
|
+
runOnJS,
|
|
18
|
+
runOnUI,
|
|
19
|
+
} from 'react-native-reanimated';
|
|
20
|
+
|
|
21
|
+
export { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import LottieView, { type LottieViewProps } from 'lottie-react-native';
|
|
3
|
+
|
|
4
|
+
export type LottieProps = LottieViewProps;
|
|
5
|
+
|
|
6
|
+
export const Lottie = forwardRef<LottieView, LottieProps>(function Lottie(
|
|
7
|
+
{ autoPlay = true, loop = true, ...rest },
|
|
8
|
+
ref,
|
|
9
|
+
) {
|
|
10
|
+
return <LottieView ref={ref} autoPlay={autoPlay} loop={loop} {...rest} />;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type LottieRef = LottieView;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useState, type ReactNode } from 'react';
|
|
2
|
+
import { Pressable, type PressableProps, type ViewStyle } from 'react-native';
|
|
3
|
+
import { EaseView } from 'react-native-ease';
|
|
4
|
+
import type {
|
|
5
|
+
AnimateProps,
|
|
6
|
+
CubicBezier,
|
|
7
|
+
EasingType,
|
|
8
|
+
EaseViewProps,
|
|
9
|
+
NoneTransition,
|
|
10
|
+
SingleTransition,
|
|
11
|
+
SpringTransition,
|
|
12
|
+
TimingTransition,
|
|
13
|
+
Transition,
|
|
14
|
+
TransitionEndEvent,
|
|
15
|
+
TransitionMap,
|
|
16
|
+
TransformOrigin,
|
|
17
|
+
TransformPerspective,
|
|
18
|
+
} from 'react-native-ease';
|
|
19
|
+
|
|
20
|
+
export type MotionPressableProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
21
|
+
animate?: AnimateProps;
|
|
22
|
+
pressedAnimate?: AnimateProps;
|
|
23
|
+
transition?: Transition;
|
|
24
|
+
style?: ViewStyle;
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function MotionPressable({
|
|
29
|
+
animate,
|
|
30
|
+
pressedAnimate,
|
|
31
|
+
transition,
|
|
32
|
+
style,
|
|
33
|
+
children,
|
|
34
|
+
onPressIn,
|
|
35
|
+
onPressOut,
|
|
36
|
+
...rest
|
|
37
|
+
}: MotionPressableProps) {
|
|
38
|
+
const [pressed, setPressed] = useState(false);
|
|
39
|
+
const current: AnimateProps | undefined =
|
|
40
|
+
pressed && pressedAnimate ? { ...animate, ...pressedAnimate } : animate;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Pressable
|
|
44
|
+
onPressIn={(e) => {
|
|
45
|
+
setPressed(true);
|
|
46
|
+
onPressIn?.(e);
|
|
47
|
+
}}
|
|
48
|
+
onPressOut={(e) => {
|
|
49
|
+
setPressed(false);
|
|
50
|
+
onPressOut?.(e);
|
|
51
|
+
}}
|
|
52
|
+
{...rest}
|
|
53
|
+
>
|
|
54
|
+
<EaseView animate={current} transition={transition} style={style}>
|
|
55
|
+
{children}
|
|
56
|
+
</EaseView>
|
|
57
|
+
</Pressable>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const Motion = {
|
|
62
|
+
View: EaseView,
|
|
63
|
+
Pressable: MotionPressable,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type {
|
|
67
|
+
AnimateProps,
|
|
68
|
+
CubicBezier,
|
|
69
|
+
EasingType,
|
|
70
|
+
EaseViewProps,
|
|
71
|
+
NoneTransition,
|
|
72
|
+
SingleTransition,
|
|
73
|
+
SpringTransition,
|
|
74
|
+
TimingTransition,
|
|
75
|
+
Transition,
|
|
76
|
+
TransitionEndEvent,
|
|
77
|
+
TransitionMap,
|
|
78
|
+
TransformOrigin,
|
|
79
|
+
TransformPerspective,
|
|
80
|
+
};
|
package/template/package.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@expo/ui": "55.0.17",
|
|
13
|
+
"@shopify/react-native-skia": "2.4.18",
|
|
13
14
|
"expo": "~55.0.26",
|
|
14
15
|
"expo-clipboard": "~55.0.13",
|
|
15
16
|
"expo-dev-client": "~55.0.35",
|
|
@@ -18,8 +19,10 @@
|
|
|
18
19
|
"expo-router": "~55.0.16",
|
|
19
20
|
"expo-status-bar": "~55.0.6",
|
|
20
21
|
"expo-symbols": "~55.0.9",
|
|
22
|
+
"lottie-react-native": "~7.3.4",
|
|
21
23
|
"react": "19.2.0",
|
|
22
24
|
"react-native": "0.83.6",
|
|
25
|
+
"react-native-ease": "^0.7.2",
|
|
23
26
|
"react-native-gesture-handler": "~2.30.1",
|
|
24
27
|
"react-native-reanimated": "4.2.1",
|
|
25
28
|
"react-native-safe-area-context": "5.6.2",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
node-linker: hoisted
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
allowBuilds:
|
|
3
|
+
cloudflared: true
|