create-proto 0.5.2 → 0.6.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.
package/dist/messages.js CHANGED
@@ -9,7 +9,7 @@ export const messages = {
9
9
  bootingProto: 'Booting Prototo...',
10
10
  nextSteps: (name) => `Keep this terminal running. It auto-refreshes your prototype.\n\nOpen a new terminal and run:\n cd ${name} && claude\n\nIn Claude, press Shift+Tab to switch to Auto mode.`,
11
11
  protoCliNotFound: (name) => `Couldn't find proto-cli. Run manually: cd ${name} && npx proto start`,
12
- howToRestart: (name) => `Proto stopped.\nTo restart Proto: cd ${name} && npx proto start\nTo prompt Claude: cd ${name} && claude`,
12
+ howToRestart: (name) => `Proto stopped.\nTo restart Proto: cd ${name} && npx proto start\nTo share a link: cd ${name} && npx proto share\nTo prompt Claude: cd ${name} && claude`,
13
13
  noNetwork: "Couldn't reach the package registry. Check your internet and try again.",
14
14
  noPermission: "Don't have permission to write here. Try a different folder.",
15
15
  noSpace: 'Out of disk space. Free some up and try again.',
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,CAAC,IAAY,EAAE,OAAgB,EAAE,EAAE,CAC5C,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,IAAI,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC,cAAc,IAAI,KAAK;IACvF,SAAS,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,gBAAgB,OAAO,GAAG;IAC1D,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAC7B,8FAA8F,IAAI,KAAK;IACzG,iBAAiB,EAAE,CAAC,IAAY,EAAE,EAAE,CAClC,qEAAqE,IAAI,iCAAiC;IAC5G,SAAS,EAAE,4BAA4B;IACvC,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE,CACjC,eAAe,IAAI,mDAAmD;IACxE,YAAY,EAAE,oBAAoB;IAClC,SAAS,EAAE,CAAC,IAAY,EAAE,EAAE,CAC1B,uGAAuG,IAAI,kEAAkE;IAC/K,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE,CACjC,6CAA6C,IAAI,qBAAqB;IACxE,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAC7B,wCAAwC,IAAI,6CAA6C,IAAI,YAAY;IAC3G,SAAS,EACP,yEAAyE;IAC3E,YAAY,EACV,8DAA8D;IAChE,OAAO,EAAE,gDAAgD;IACzD,aAAa,EACX,mEAAmE;CACtE,CAAC"}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,CAAC,IAAY,EAAE,OAAgB,EAAE,EAAE,CAC5C,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,IAAI,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC,cAAc,IAAI,KAAK;IACvF,SAAS,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,gBAAgB,OAAO,GAAG;IAC1D,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAC7B,8FAA8F,IAAI,KAAK;IACzG,iBAAiB,EAAE,CAAC,IAAY,EAAE,EAAE,CAClC,qEAAqE,IAAI,iCAAiC;IAC5G,SAAS,EAAE,4BAA4B;IACvC,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE,CACjC,eAAe,IAAI,mDAAmD;IACxE,YAAY,EAAE,oBAAoB;IAClC,SAAS,EAAE,CAAC,IAAY,EAAE,EAAE,CAC1B,uGAAuG,IAAI,kEAAkE;IAC/K,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE,CACjC,6CAA6C,IAAI,qBAAqB;IACxE,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAC7B,wCAAwC,IAAI,4CAA4C,IAAI,6CAA6C,IAAI,YAAY;IAC3J,SAAS,EACP,yEAAyE;IAC3E,YAAY,EACV,8DAA8D;IAChE,OAAO,EAAE,gDAAgD;IACzD,aAAa,EACX,mEAAmE;CACtE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-proto",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
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",
@@ -35,14 +35,14 @@
35
35
  "LICENSE"
36
36
  ],
37
37
  "engines": {
38
- "node": ">=18"
38
+ "node": ">=20"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
44
  "@clack/prompts": "^0.7.0",
45
- "@sherizan/proto-cli": "^0.5.0",
45
+ "@sherizan/proto-cli": "^0.6.0",
46
46
  "fs-extra": "^11.2.0",
47
47
  "qrcode-terminal": "^0.12.0",
48
48
  "validate-npm-package-name": "^5.0.1"
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "prototo": {
4
+ "command": "npx",
5
+ "args": ["proto-mcp"]
6
+ }
7
+ }
8
+ }
@@ -76,6 +76,19 @@ You can't see the Simulator by default, so after any visual change, look at it:
76
76
 
77
77
  Do this especially after layout, color, typography, or spacing changes. If `proto shot` reports no preview is running, the designer needs to run `proto start` first.
78
78
 
79
+ ## Proto MCP tools
80
+
81
+ When the designer runs `proto start`, a local MCP server (`prototo`) connects automatically — no setup. It gives you two tools that close the feedback loop, so you can see what you built instead of asking the designer to relay it.
82
+
83
+ **After every screen write:**
84
+
85
+ 1. Call `compile_check` with the screen name — it type-checks the project and reports any problems in plain language. Fix anything it surfaces before moving on.
86
+ 2. Call `get_simulator_screenshot` — it returns what the prototype actually renders right now. Inspect it for the same defects as above.
87
+
88
+ Never assume a screen rendered correctly — check the screenshot. Never ask the designer to describe an error you can catch with `compile_check`. If a tool says the Simulator isn't running, the designer needs to run `proto start` first.
89
+
90
+ (`get_simulator_screenshot` is the automated form of the `proto shot` loop above — prefer the tool when it's available.)
91
+
79
92
  ## Mock vs real data
80
93
 
81
94
  When a screen shows placeholder numbers that aren't yet wired to a real source, wrap them in `mock()` from `../components/proto` — `const conditions = mock({ wave: '0.8m' })`. It returns the value unchanged, so nothing breaks; it just makes stubbed data obvious and greppable so fake numbers never ship believing they're real. When you wire the value to a live source (a `fetch`), drop the `mock()` wrapper. (Don't use code comments to mark mock data — generated screens stay comment-free.)
@@ -106,6 +119,12 @@ When the designer says "use real data", follow this shape so every screen handle
106
119
 
107
120
  **Keyless APIs** (no key, CORS-open, good for prototypes): Open-Meteo (weather/marine/air), REST Countries, Open Library, PokéAPI, Art Institute of Chicago, TheMealDB, Wikipedia REST. Prefer these so "make it real" stays a one-prompt step. If a source needs a key, tell the designer that key goes in `proto.config.js`, nowhere else.
108
121
 
122
+ ## Sharing your prototype
123
+
124
+ Run `proto share` to publish the prototype and get a `prototo.app/p/<token>` link. Anyone can open it in a browser — no install — and see the **real prototype running**, streamed live from a cloud iPhone. Full fidelity: gestures, `motion`/`gestures`/`canvas`/`svg`/`lottie`, live data, and custom logic all show up in the shared link exactly as they run on the designer's device. There's nothing to dumb down — build whatever the designer asks for and it all shares.
125
+
126
+ Two limits worth knowing: the prototype must be built on the **current Prototo** (an older one won't stream — re-scaffold if prompted), and **real-hardware features** (camera, GPS) are simulated on the cloud device rather than reading a real sensor.
127
+
109
128
  ## When modifying
110
129
 
111
130
  Read the file first, then make precise, targeted edits to the parts that change. Keep edits scoped — don't rewrite a whole file when a few lines change.
@@ -5,4 +5,5 @@ Built with Prototo.
5
5
  Before running `proto start` on iPhone, install Prototo from the App Store.
6
6
 
7
7
  Run `proto start` to preview on the iOS Simulator (auto) or your iPhone (scan QR).
8
+ Run `proto share` to get a link anyone can open in their browser, no install needed.
8
9
  Run `proto add "describe a screen"` to generate a new screen.
@@ -1,4 +1,5 @@
1
- import { Modal as RNModal, Pressable, View } from 'react-native';
1
+ import { Modal as RNModal, View } from 'react-native';
2
+ import { SafeAreaView } from 'react-native-safe-area-context';
2
3
  import type { ReactNode } from 'react';
3
4
  import { useTheme } from './useTheme';
4
5
  import { Text } from './Text';
@@ -10,34 +11,27 @@ export type ModalProps = {
10
11
  children?: ReactNode;
11
12
  };
12
13
 
14
+ /**
15
+ * Modal presented as iOS 26's native page sheet (UISheetPresentationController):
16
+ * native spring-in, backdrop dim, the screen behind receding, and swipe-to-dismiss
17
+ * — no hand-rolled overlay. onClose fires on both the swipe-dismiss (onRequestClose)
18
+ * and programmatic close.
19
+ */
13
20
  export function Modal({ title, visible, onClose, children }: ModalProps) {
14
21
  const theme = useTheme();
15
22
  return (
16
23
  <RNModal
17
24
  visible={visible}
18
- transparent
19
25
  animationType="slide"
26
+ presentationStyle="pageSheet"
20
27
  onRequestClose={onClose}
21
28
  >
22
- <Pressable
23
- onPress={onClose}
24
- style={{ flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.4)' }}
25
- >
26
- <Pressable
27
- onPress={() => {}}
28
- style={{
29
- marginTop: 'auto',
30
- backgroundColor: theme.surface.primary,
31
- borderTopLeftRadius: theme.radius.modal,
32
- borderTopRightRadius: theme.radius.modal,
33
- padding: theme.space.lg,
34
- gap: theme.space.md,
35
- }}
36
- >
29
+ <SafeAreaView style={{ flex: 1, backgroundColor: theme.surface.primary }} edges={['bottom']}>
30
+ <View style={{ flex: 1, padding: theme.space.lg, gap: theme.space.md }}>
37
31
  <Text size="headline">{title}</Text>
38
32
  {children}
39
- </Pressable>
40
- </Pressable>
33
+ </View>
34
+ </SafeAreaView>
41
35
  </RNModal>
42
36
  );
43
37
  }
@@ -0,0 +1,29 @@
1
+ import { type ReactNode, createContext, useContext } from 'react';
2
+ import defaultConfigModule from '../../proto.config.js';
3
+ import type { ProtoConfig } from './types';
4
+
5
+ // The static `proto.config.js` at the project root is the default. Scaffolded
6
+ // projects render screens directly (no provider) and fall back to it, so their
7
+ // behaviour is unchanged. The manifest renderer wraps its tree in
8
+ // <ProtoConfigProvider config={manifest.app}> to drive theme from a manifest.
9
+ const defaultConfig = defaultConfigModule as ProtoConfig;
10
+
11
+ const ProtoConfigContext = createContext<ProtoConfig | null>(null);
12
+
13
+ export function ProtoConfigProvider({
14
+ config,
15
+ children,
16
+ }: {
17
+ config?: ProtoConfig;
18
+ children: ReactNode;
19
+ }) {
20
+ return (
21
+ <ProtoConfigContext.Provider value={config ?? defaultConfig}>
22
+ {children}
23
+ </ProtoConfigContext.Provider>
24
+ );
25
+ }
26
+
27
+ export function useProtoConfig(): ProtoConfig {
28
+ return useContext(ProtoConfigContext) ?? defaultConfig;
29
+ }
@@ -8,6 +8,7 @@ export { Toggle, type ToggleProps } from './Toggle';
8
8
  export { Divider } from './Divider';
9
9
  export { Modal, type ModalProps } from './Modal';
10
10
  export { useTheme, useAccent } from './useTheme';
11
+ export { ProtoConfigProvider, useProtoConfig } from './ProtoConfigContext';
11
12
  export { mock } from './mock';
12
13
  export { a11y } from './a11y';
13
14
  export type { Theme, ThemeName, ThemeOverrides, ProtoConfig } from './types';
@@ -1,9 +1,9 @@
1
1
  import { useColorScheme } from 'react-native';
2
- import config from '../../proto.config.js';
2
+ import { useProtoConfig } from './ProtoConfigContext';
3
3
  import { base, baseDark } from './tokens/base';
4
4
  import { liquidGlass, liquidGlassDark } from './tokens/liquidGlass';
5
5
  import { materialYou, materialYouDark } from './tokens/materialYou';
6
- import type { ProtoConfig, Theme, ThemeName, ThemeOverrides } from './types';
6
+ import type { Theme, ThemeName, ThemeOverrides } from './types';
7
7
 
8
8
  const lightThemes: Record<ThemeName, Theme> = {
9
9
  liquidGlass,
@@ -29,13 +29,14 @@ function mergeTheme(base: Theme, overrides?: ThemeOverrides): Theme {
29
29
  };
30
30
  }
31
31
 
32
- const cfg = config as ProtoConfig;
33
-
34
32
  // A hook — it reads the system colour scheme so screens re-render when the device
35
33
  // switches between light and dark. Call it during render, like any hook.
36
- // `proto.config.js` can pin a scheme with `colorScheme: 'light' | 'dark'`; the
37
- // default ('system') follows the device.
34
+ // Config comes from the nearest <ProtoConfigProvider> (the manifest renderer sets
35
+ // one) or, with no provider, the project's static `proto.config.js`. A scheme can
36
+ // be pinned with `colorScheme: 'light' | 'dark'`; the default ('system') follows
37
+ // the device.
38
38
  export function useTheme(): Theme {
39
+ const cfg = useProtoConfig();
39
40
  const systemScheme = useColorScheme();
40
41
  const preference = cfg.colorScheme ?? 'system';
41
42
  const isDark = preference === 'dark' || (preference === 'system' && systemScheme === 'dark');
@@ -47,5 +48,5 @@ export function useTheme(): Theme {
47
48
  }
48
49
 
49
50
  export function useAccent(): string {
50
- return cfg.accentColor ?? '#007AFF';
51
+ return useProtoConfig().accentColor ?? '#007AFF';
51
52
  }
@@ -9,47 +9,49 @@
9
9
  "proto": "proto"
10
10
  },
11
11
  "dependencies": {
12
- "@expo/ui": "55.0.17",
12
+ "@expo/ui": "~56.0.16",
13
13
  "@react-native-async-storage/async-storage": "2.2.0",
14
14
  "@shopify/flash-list": "2.0.2",
15
- "@shopify/react-native-skia": "2.4.18",
16
- "expo": "~55.0.26",
17
- "expo-asset": "~55.0.17",
18
- "expo-audio": "~55.0.14",
19
- "expo-camera": "~55.0.18",
20
- "expo-clipboard": "~55.0.13",
21
- "expo-dev-client": "~55.0.35",
22
- "expo-font": "~55.0.8",
23
- "expo-glass-effect": "~55.0.11",
24
- "expo-haptics": "~55.0.14",
25
- "expo-image": "~55.0.11",
26
- "expo-image-picker": "~55.0.20",
27
- "expo-linear-gradient": "~55.0.14",
28
- "expo-location": "~55.1.10",
29
- "expo-maps": "~55.0.19",
30
- "expo-router": "~55.0.16",
31
- "expo-status-bar": "~55.0.6",
32
- "expo-symbols": "~55.0.9",
33
- "expo-video": "~55.0.17",
15
+ "@shopify/react-native-skia": "2.6.2",
16
+ "expo": "~56.0.0",
17
+ "expo-asset": "~56.0.16",
18
+ "expo-audio": "~56.0.11",
19
+ "expo-camera": "~56.0.7",
20
+ "expo-clipboard": "~56.0.4",
21
+ "expo-constants": "~56.0.17",
22
+ "expo-dev-client": "~56.0.19",
23
+ "expo-font": "~56.0.5",
24
+ "expo-glass-effect": "~56.0.4",
25
+ "expo-haptics": "~56.0.3",
26
+ "expo-image": "~56.0.10",
27
+ "expo-image-picker": "~56.0.16",
28
+ "expo-linear-gradient": "~56.0.4",
29
+ "expo-linking": "~56.0.13",
30
+ "expo-location": "~56.0.16",
31
+ "expo-maps": "~56.0.6",
32
+ "expo-router": "~56.2.9",
33
+ "expo-status-bar": "~56.0.4",
34
+ "expo-symbols": "~56.0.6",
35
+ "expo-video": "~56.1.2",
34
36
  "lottie-react-native": "~7.3.4",
35
- "react": "19.2.0",
36
- "react-dom": "19.2.0",
37
- "react-native": "0.83.6",
37
+ "react": "19.2.3",
38
+ "react-dom": "19.2.3",
39
+ "react-native": "0.85.3",
38
40
  "react-native-ease": "^0.7.2",
39
- "react-native-gesture-handler": "~2.30.1",
40
- "react-native-reanimated": "4.2.1",
41
- "react-native-safe-area-context": "5.6.2",
42
- "react-native-screens": "4.23.0",
43
- "react-native-svg": "15.15.3",
44
- "react-native-webview": "13.16.0",
45
- "react-native-worklets": "0.7.4"
41
+ "react-native-gesture-handler": "~2.31.1",
42
+ "react-native-reanimated": "4.3.1",
43
+ "react-native-safe-area-context": "~5.7.0",
44
+ "react-native-screens": "4.25.2",
45
+ "react-native-svg": "15.15.4",
46
+ "react-native-webview": "13.16.1",
47
+ "react-native-worklets": "0.8.3"
46
48
  },
47
49
  "devDependencies": {
48
50
  "@babel/core": "^7.24.0",
49
- "@sherizan/proto-cli": "^0.5.0",
51
+ "@sherizan/proto-cli": "^0.6.0",
50
52
  "@types/react": "~19.2.15",
51
- "babel-preset-expo": "~55.0.22",
53
+ "babel-preset-expo": "~56.0.0",
52
54
  "react-native-svg-transformer": "^1.5.0",
53
- "typescript": "^5.9.2"
55
+ "typescript": "~6.0.3"
54
56
  }
55
57
  }