create-proto 0.1.6 → 0.1.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-proto",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
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.1.6",
45
+ "@sherizan/proto-cli": "^0.1.8",
46
46
  "fs-extra": "^11.2.0",
47
47
  "qrcode-terminal": "^0.12.0",
48
48
  "validate-npm-package-name": "^5.0.1"
@@ -1,71 +1,53 @@
1
1
  # Proto Project — Claude Code Instructions
2
2
 
3
- You are the design tool inside a Proto project. The iOS Simulator is the canvas. The designer prompts you in plain language; you generate native iOS screens following the design system in DESIGN.md. Designers never touch files.
3
+ You're the design tool inside a Proto project. The designer prompts you in plain language; you generate native iOS screens. The iOS Simulator is the canvas. Designers never touch files.
4
4
 
5
- ## Three rules
5
+ ## Read first
6
+ - `DESIGN.md` — design tokens and the project's decisions
7
+ - `/screens/` — what already exists
6
8
 
7
- **1. Native iOS first.** Apple's components automatically get Liquid Glass, SF Symbols, system tints, haptics, accessibility, and dynamic type. Always prefer them when they exist:
9
+ ## Building blocks (use whatever fits)
8
10
 
9
- | Need | Use |
10
- |---|---|
11
- | Tab bar | `expo-router/unstable-native-tabs` (`NativeTabs` + `Icon sf={{default, selected}}` in `app/_layout.tsx`) |
12
- | SF Symbol icon | `expo-symbols` `SymbolView` |
13
- | System button | `@expo/ui/swift-ui` `Button` |
14
- | System toggle | `@expo/ui/swift-ui` `Toggle` |
15
- | Form / settings list | `@expo/ui/swift-ui` `Form` + `Section` |
16
- | Liquid Glass surface | `expo-glass-effect` `GlassView` directly |
11
+ **Native iOS** the easiest path to system-feel UI. Apple handles Liquid Glass, SF Symbols, accessibility, dynamic type:
17
12
 
18
- Never wrap a native component just to add Proto branding. Native > custom.
13
+ - `expo-router/unstable-native-tabs` native `UITabBar`
14
+ - `expo-router` `Stack` with `headerLargeTitle: true` + `title` set per route — native large-title nav bar. Don't add `headerTransparent` or `headerBlurEffect` — iOS 26's UINavigationBar paints Liquid Glass automatically and those props break the large-title rendering / cause overlapping effects.
15
+ - `expo-symbols` `SymbolView` — SF Symbol icons
16
+ - `@expo/ui/swift-ui` — `Button`, `Toggle`, `Form`, `Section`, etc.
17
+ - `expo-glass-effect` `GlassView` — Liquid Glass surfaces
19
18
 
20
- **2. Proto primitives are fallbacks for what native doesn't ship.** Use `/components/proto` for layout helpers, generic surfaces, themed text never to rebuild Apple-native UI.
19
+ **Proto 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.
21
20
 
22
- **3. DESIGN.md is the only source of design tokens.** Read it before every change. Never hardcode colour, spacing, radius, or typography. If the designer asks to change tokens, update DESIGN.md.
23
-
24
- If DESIGN.md's "Component Library" section names a third-party library (Tamagui, Gluestack, etc.), use that library's components first, Proto primitives as fallback. Otherwise use Proto primitives only.
21
+ **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; the primitives are starting points, not constraints.
25
22
 
26
23
  ## File layout
27
24
 
28
25
  ```
29
- /app/<route>.tsx thin re-export of a screen (one-line wrapper)
30
- /app/_layout.tsx NativeTabs root layout (when app has tabs)
31
- /screens/<Name>.tsx actual screen component (PascalCase, default export)
32
- /components/shared/ designer-created shared components
33
- /components/proto/ Proto primitives — read-only, do not edit
26
+ /app/<route>.tsx route one-line re-export
27
+ /app/_layout.tsx Stack (for native large titles) or NativeTabs (for tabs)
28
+ /screens/<Name>.tsx screen, PascalCase, default export
29
+ /components/shared/ designer-created custom components
30
+ /components/proto/ Proto primitives — read-only
34
31
  ```
35
32
 
36
- For a new screen `screens/Settings.tsx`, add a matching `app/settings.tsx`:
37
-
38
- ```tsx
39
- import Settings from '../screens/Settings';
40
- export default function SettingsRoute() { return <Settings />; }
41
- ```
33
+ A new screen `screens/Settings.tsx` needs:
34
+ - `app/settings.tsx` re-exporting it (`import Settings from '../screens/Settings'; export default function SettingsRoute() { return <Settings />; }`)
35
+ - A title set in `app/_layout.tsx`: `<Stack.Screen name="settings" options={{ title: 'Settings' }} />`
36
+ - Route filenames are lowercase kebab-case.
42
37
 
43
- Route filenames are lowercase kebab-case. Then add a one-line description to the Screens section of DESIGN.md.
38
+ ## DESIGN.md is alive
44
39
 
45
- ## Proto primitives (`/components/proto`)
40
+ When the designer asks to change colors, typography, spacing, shape, accent, or anything design-systemy, update `DESIGN.md` too. It's the project's source of truth, and other tools (and future you) will read it.
46
41
 
47
- ```
48
- Screen title?, scrollable? SafeAreaView + ScrollView wrapper
49
- Stack gap?, padding? vertical flex
50
- Row gap?, align? horizontal flex
51
- Text size, color, style? themed RN Text (sizes: title/headline/body/caption/label)
52
- Card glass?, padding? surface; glass={true} = real Liquid Glass on iOS 26+
53
- Button label, variant?, onPress custom animated button — for iOS system style use @expo/ui Button
54
- Toggle label, value, onChange themed RN Switch — for iOS system look use @expo/ui Toggle
55
- Divider — 1px separator
56
- Modal title?, visible, ... RN Modal wrapper
57
- ```
42
+ When you add a new screen, add a one-line entry to `DESIGN.md`'s Screens section.
58
43
 
59
- ## When modifying a screen
44
+ ## When modifying
60
45
 
61
- Read the file first, then rewrite the full file. Never partial edits or diffs.
46
+ Read the file first, rewrite the full file. Never partial edits.
62
47
 
63
- ## Never
48
+ ## Avoid
64
49
 
65
- - Never import from `react-native` directly use a library, native iOS, or Proto fallback
66
- - Never build a custom tab baralways `expo-router/unstable-native-tabs`
67
- - Never put logic in `/app/` files — they re-export a screen, nothing else
68
- - Never use SF Symbol private-use Unicode codepoints (like `''`) as text they don't render in plain Text. Use `expo-symbols` `SymbolView` or native components that take SF symbol names
69
- - Never edit `/components/proto/`, `.proto/`, `app.config.js`, `babel.config.js`, `metro.config.js`
70
- - Never add a build step, dependency, or visual editor
71
- - Never tell the designer to open or edit a file manually
50
+ - Custom tab bars `expo-router/unstable-native-tabs` is strictly better (real Liquid Glass, real SF Symbols, system blur).
51
+ - SF Symbol private-use Unicode codepoints (`''`, `''`) in plain Text they don't render. Use `expo-symbols` `SymbolView` or pass the symbol name to a native component.
52
+ - Editing `/components/proto/`, `.proto/`, `app.config.js`, `babel.config.js`, `metro.config.js`.
53
+ - Telling the designer to open or edit a file manually. They prompt; you write.
@@ -1,69 +1,34 @@
1
1
  # DESIGN.md
2
2
 
3
- > The design system for {{APP_NAME}}. Read by Claude Code before every change.
3
+ > {{APP_NAME}}'s design system. These are starting defaults change anything by prompting Claude.
4
+ >
5
+ > Examples:
6
+ > - `update DESIGN.md, change accent to indigo`
7
+ > - `double the spacing scale`
8
+ > - `use SF Pro Rounded for headlines`
9
+ > - `add a brand purple to the palette`
10
+ >
4
11
  > Last updated: {{DATE}}
5
12
 
6
- ## How to update this file
7
-
8
- You never edit this file directly. Tell Claude Code in plain language and it rewrites the relevant section. Examples:
9
-
10
- - `update DESIGN.md, change accent to indigo and apply it everywhere`
11
- - `make card corners tighter — radius 16 instead of 22`
12
- - `switch to dark mode`
13
- - `use Tamagui as the component library`
14
-
15
- The tokens below become the actual colours, typography, and spacing in your screens. Never hardcoded.
16
-
17
13
  ## App
18
14
  - Name: {{APP_NAME}}
19
- - Theme: liquidGlass
20
- - Platform: iOS 26+ (Liquid Glass renders natively; iOS < 26 falls back to standard blur)
21
-
22
- ## Component library
23
- - Package: proto (built-in fallback)
24
- - Import from: ../components/proto
25
- - Fallback: proto
26
-
27
- For native iOS surfaces (tab bars, SF Symbols, system buttons, toggles, forms, Liquid Glass), Claude reaches for Apple-native components first — see CLAUDE.md.
28
-
29
- ## Colour
30
- - Accent: #007AFF
31
- - Surface primary: rgba(255,255,255,0.72)
32
- - Surface secondary: rgba(255,255,255,0.48)
33
- - Surface card: rgba(255,255,255,0.60)
34
- - Surface nav: rgba(255,255,255,0.82)
35
- - Text primary: #000000
36
- - Text secondary: rgba(0,0,0,0.5)
37
- - Text tertiary: rgba(0,0,0,0.3)
38
- - Destructive: #FF3B30
39
-
40
- ## Typography
41
- - Title: 34px / bold / tracking -0.4
42
- - Headline: 22px / semibold / tracking -0.4
43
- - Body: 17px / regular
44
- - Caption: 12px / regular / text-secondary
45
- - Label: 13px / medium
15
+ - Platform: iOS
46
16
 
47
- ## Spacing
48
- - xs: 4 / sm: 8 / md: 16 / lg: 24 / xl: 32
17
+ ## Tokens
49
18
 
50
- ## Shape
51
- - Card radius: 22
52
- - Button radius: 14
53
- - Modal radius: 44
54
- - Input radius: 12
19
+ ### Accent
20
+ #007AFF (iOS system blue)
55
21
 
56
- ## Effects
57
- - Card blur: 20
58
- - Nav blur: 40
59
- - Modal blur: 60
60
- - Border: rgba(255,255,255,0.4)
22
+ ### Type
23
+ iOS system font with dynamic type defaults. Override per-size below if you need custom sizing.
61
24
 
62
- ## Components in use
25
+ ### Spacing
26
+ xs 4 · sm 8 · md 16 · lg 24 · xl 32
63
27
 
64
- **Proto primitives** — Screen, Stack, Row, Text, Card, Button, Toggle, Modal, Divider.
28
+ ### Surface
29
+ Apple Liquid Glass via `expo-glass-effect` (iOS 26+ native material). On older iOS it falls back to a plain surface — Proto targets iOS 26.
65
30
 
66
- **Native iOS** UITabBar (via `expo-router/unstable-native-tabs`), SF Symbols (via `expo-symbols`), SwiftUI primitives (via `@expo/ui/swift-ui`), Liquid Glass surfaces (via `expo-glass-effect`).
31
+ (Add your own tokens below as you describe what you want. Claude rewrites this file as the design system evolves.)
67
32
 
68
33
  ## Screens
69
- - Home (initial) starter screen
34
+ - Home — welcome screen with tutorial prompts
@@ -0,0 +1,15 @@
1
+ import { Stack } from 'expo-router';
2
+
3
+ export default function RootLayout() {
4
+ return (
5
+ <Stack>
6
+ <Stack.Screen
7
+ name="index"
8
+ options={{
9
+ title: 'Proto',
10
+ headerLargeTitle: true,
11
+ }}
12
+ />
13
+ </Stack>
14
+ );
15
+ }
@@ -1,6 +1,5 @@
1
1
  import { View } from 'react-native';
2
- import { BlurView } from 'expo-blur';
3
- import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
2
+ import { GlassView } from 'expo-glass-effect';
4
3
  import type { ReactNode } from 'react';
5
4
  import { useTheme } from './useTheme';
6
5
 
@@ -10,40 +9,33 @@ export type CardProps = {
10
9
  children?: ReactNode;
11
10
  };
12
11
 
12
+ /**
13
+ * Card surface.
14
+ *
15
+ * glass={true}: Apple Liquid Glass via expo-glass-effect's GlassView. On
16
+ * iOS 26+ this paints the real native material that refracts content behind
17
+ * it. On older iOS GlassView falls back to a plain View — no third-party
18
+ * blur. Proto targets iOS 26 and only uses Apple's native material.
19
+ *
20
+ * Plain (no glass): opaque surface with theme tokens.
21
+ */
13
22
  export function Card({ glass = false, padding, children }: CardProps) {
14
23
  const theme = useTheme();
15
24
  const pad = padding ?? theme.space.md;
16
25
 
17
26
  if (glass) {
18
- if (isLiquidGlassAvailable()) {
19
- return (
20
- <GlassView
21
- style={{
22
- borderRadius: theme.radius.card,
23
- borderWidth: 1,
24
- borderColor: theme.border.default,
25
- padding: pad,
26
- overflow: 'hidden',
27
- }}
28
- >
29
- {children}
30
- </GlassView>
31
- );
32
- }
33
27
  return (
34
- <View
28
+ <GlassView
35
29
  style={{
36
30
  borderRadius: theme.radius.card,
37
- overflow: 'hidden',
38
31
  borderWidth: 1,
39
32
  borderColor: theme.border.default,
40
- backgroundColor: theme.surface.card,
33
+ padding: pad,
34
+ overflow: 'hidden',
41
35
  }}
42
36
  >
43
- <BlurView intensity={theme.blur.card} tint="light" style={{ padding: pad }}>
44
- {children}
45
- </BlurView>
46
- </View>
37
+ {children}
38
+ </GlassView>
47
39
  );
48
40
  }
49
41
 
@@ -2,47 +2,48 @@ import { ScrollView, View } from 'react-native';
2
2
  import { SafeAreaView } from 'react-native-safe-area-context';
3
3
  import type { ReactNode } from 'react';
4
4
  import { useTheme } from './useTheme';
5
- import { Text } from './Text';
6
5
 
7
6
  export type ScreenProps = {
8
- title?: string;
9
7
  scrollable?: boolean;
10
8
  children?: ReactNode;
11
9
  };
12
10
 
13
- export function Screen({ title, scrollable = true, children }: ScreenProps) {
11
+ /**
12
+ * Screen wrapper for iOS 26+.
13
+ *
14
+ * Scrollable (default): the ScrollView is the top-level element so the native
15
+ * UINavigationBar can track it for large-title scroll behavior — the big
16
+ * title shrinks to a compact inline title as content scrolls up. iOS's
17
+ * automatic content insets handle the transparent nav bar and home indicator.
18
+ *
19
+ * Non-scrollable: SafeAreaView guards bottom + side edges (no scroll to track).
20
+ *
21
+ * Background lives on the outermost element so it covers bounce / inset areas.
22
+ * For Liquid Glass surfaces inside (cards, sheets), use Card with glass={true}
23
+ * — it wraps expo-glass-effect's GlassView, iOS 26's native material.
24
+ */
25
+ export function Screen({ scrollable = true, children }: ScreenProps) {
14
26
  const theme = useTheme();
15
- const Body = scrollable ? ScrollView : View;
27
+ const padding = theme.space.md;
28
+
29
+ if (scrollable) {
30
+ return (
31
+ <ScrollView
32
+ style={{ flex: 1, backgroundColor: theme.surface.primary }}
33
+ contentContainerStyle={{ padding, gap: padding }}
34
+ contentInsetAdjustmentBehavior="automatic"
35
+ >
36
+ {children}
37
+ </ScrollView>
38
+ );
39
+ }
40
+
16
41
  return (
17
- <View style={{ flex: 1, backgroundColor: theme.surface.primary }}>
18
- <SafeAreaView style={{ flex: 1 }} edges={['top', 'left', 'right']}>
19
- {title ? (
20
- <View
21
- style={{
22
- paddingHorizontal: theme.space.md,
23
- paddingBottom: theme.space.xs,
24
- }}
25
- >
26
- <Text size="title">{title}</Text>
27
- </View>
28
- ) : null}
29
- <Body
30
- style={{ flex: 1 }}
31
- contentContainerStyle={
32
- scrollable
33
- ? { padding: theme.space.md, gap: theme.space.md }
34
- : undefined
35
- }
36
- >
37
- {scrollable ? (
38
- children
39
- ) : (
40
- <View style={{ flex: 1, padding: theme.space.md, gap: theme.space.md }}>
41
- {children}
42
- </View>
43
- )}
44
- </Body>
45
- </SafeAreaView>
46
- </View>
42
+ <SafeAreaView
43
+ style={{ flex: 1, backgroundColor: theme.surface.primary }}
44
+ edges={['bottom', 'left', 'right']}
45
+ >
46
+ <View style={{ flex: 1, padding, gap: padding }}>{children}</View>
47
+ </SafeAreaView>
47
48
  );
48
49
  }
@@ -4,7 +4,7 @@ export const liquidGlass: Theme = {
4
4
  surface: {
5
5
  primary: 'rgba(255, 255, 255, 0.72)',
6
6
  secondary: 'rgba(255, 255, 255, 0.48)',
7
- card: 'rgba(255, 255, 255, 0.6)',
7
+ card: '#f3f5f8',
8
8
  nav: 'rgba(255, 255, 255, 0.82)',
9
9
  },
10
10
  text: {
@@ -19,8 +19,8 @@ export const liquidGlass: Theme = {
19
19
  modal: 60,
20
20
  },
21
21
  border: {
22
- default: 'rgba(255, 255, 255, 0.4)',
23
- strong: 'rgba(255, 255, 255, 0.7)',
22
+ default: 'rgba(0, 0, 0, 0.08)',
23
+ strong: 'rgba(0, 0, 0, 0.16)',
24
24
  },
25
25
  radius: {
26
26
  card: 22,
@@ -11,7 +11,7 @@
11
11
  "dependencies": {
12
12
  "@expo/ui": "55.0.17",
13
13
  "expo": "~55.0.26",
14
- "expo-blur": "~55.0.14",
14
+ "expo-clipboard": "~8.0.7",
15
15
  "expo-glass-effect": "~55.0.11",
16
16
  "expo-haptics": "~55.0.14",
17
17
  "expo-router": "~55.0.16",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "devDependencies": {
28
28
  "@babel/core": "^7.24.0",
29
- "@sherizan/proto-cli": "^0.1.6",
29
+ "@sherizan/proto-cli": "^0.1.8",
30
30
  "@types/react": "~19.2.15",
31
31
  "babel-preset-expo": "~55.0.22",
32
32
  "typescript": "^5.9.2"
@@ -1,4 +1,7 @@
1
- import { useEffect } from 'react';
1
+ import { useEffect, useState } from 'react';
2
+ import { Pressable } from 'react-native';
3
+ import * as Clipboard from 'expo-clipboard';
4
+ import * as Haptics from 'expo-haptics';
2
5
  import Animated, {
3
6
  useSharedValue,
4
7
  useAnimatedStyle,
@@ -20,6 +23,32 @@ const STEPS = [
20
23
  },
21
24
  ];
22
25
 
26
+ function TutorialCard({ step }: { step: (typeof STEPS)[number] }) {
27
+ const [copied, setCopied] = useState(false);
28
+
29
+ const handleCopy = async () => {
30
+ await Clipboard.setStringAsync(step.prompt);
31
+ await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
32
+ setCopied(true);
33
+ setTimeout(() => setCopied(false), 1500);
34
+ };
35
+
36
+ return (
37
+ <Card padding={20}>
38
+ <Stack gap={10}>
39
+ <Row gap={10} align="center">
40
+ <Text size="headline">{step.n}.</Text>
41
+ <Text size="headline">{step.title}</Text>
42
+ </Row>
43
+ <Text size="body" color="secondary">{step.prompt}</Text>
44
+ <Pressable onPress={handleCopy} style={{ alignSelf: 'flex-end', marginTop: 4 }}>
45
+ <Text size="caption" color="accent">{copied ? 'Copied' : 'Copy'}</Text>
46
+ </Pressable>
47
+ </Stack>
48
+ </Card>
49
+ );
50
+ }
51
+
23
52
  export default function Home() {
24
53
  const opacity = useSharedValue(0);
25
54
  const translateY = useSharedValue(12);
@@ -35,14 +64,14 @@ export default function Home() {
35
64
  }));
36
65
 
37
66
  return (
38
- <Screen title="Proto" scrollable>
39
- <Stack gap={24} padding={20}>
67
+ <Screen scrollable>
68
+ <Stack gap={24}>
40
69
  <Animated.View style={heroStyle}>
41
70
  <Card glass padding={24}>
42
71
  <Stack gap={8}>
43
- <Text size="title">You're in.</Text>
72
+ <Text size="headline">You're in.</Text>
44
73
  <Text size="body" color="secondary">
45
- Try these prompts in Claude Code in Auto mode (press Shift+Tab).
74
+ {`In a terminal: cd {{APP_NAME}} && claude. Paste a prompt below.`}
46
75
  </Text>
47
76
  </Stack>
48
77
  </Card>
@@ -50,17 +79,7 @@ export default function Home() {
50
79
 
51
80
  <Stack gap={12}>
52
81
  {STEPS.map((step) => (
53
- <Card key={step.n} padding={20}>
54
- <Stack gap={10}>
55
- <Row gap={10} align="center">
56
- <Text size="headline" color="accent">{step.n}.</Text>
57
- <Text size="headline">{step.title}</Text>
58
- </Row>
59
- <Text size="body" color="accent" style={{ fontFamily: 'Menlo' }}>
60
- {step.prompt}
61
- </Text>
62
- </Stack>
63
- </Card>
82
+ <TutorialCard key={step.n} step={step} />
64
83
  ))}
65
84
  </Stack>
66
85