@shaykec/app-agent 1.0.8 → 1.0.10
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/.claude/agents/android-customizer.md +9 -1
- package/.claude/agents/catalog-analyzer.md +57 -0
- package/.claude/agents/ios-customizer.md +9 -1
- package/.claude/agents/react-native-customizer.md +71 -0
- package/.claude/skills/android-customizer/SKILL.md +108 -23
- package/.claude/skills/bug-fixer/SKILL.md +59 -0
- package/.claude/skills/catalog-analyzer/SKILL.md +96 -0
- package/.claude/skills/customization-planner/SKILL.md +44 -5
- package/.claude/skills/design-selector/SKILL.md +3 -1
- package/.claude/skills/design-system/SKILL.md +1 -1
- package/.claude/skills/exploratory-tester/SKILL.md +82 -0
- package/.claude/skills/ios-customizer/SKILL.md +123 -23
- package/.claude/skills/module-integrator/SKILL.md +1 -1
- package/.claude/skills/react-native-customizer/SKILL.md +97 -11
- package/.claude/skills/test-planner/SKILL.md +72 -0
- package/.cursor/agents/README.md +3 -1
- package/.cursor/agents/android-customizer.md +15 -11
- package/.cursor/agents/catalog-analyzer.md +83 -0
- package/.cursor/agents/ios-customizer.md +15 -10
- package/.cursor/agents/react-native-customizer.md +170 -0
- package/.cursor/mcp.json +2 -10
- package/.cursor/rules/safety-guardrails.mdc +1 -1
- package/.cursor/rules/workflow.mdc +52 -18
- package/.cursor/skills/android-customizer/SKILL.md +46 -22
- package/.cursor/skills/bug-fixer/SKILL.md +189 -0
- package/.cursor/skills/catalog-analyzer/SKILL.md +222 -0
- package/.cursor/skills/customization-planner/SKILL.md +55 -8
- package/.cursor/skills/design-selector/SKILL.md +6 -5
- package/.cursor/skills/design-system/SKILL.md +8 -7
- package/.cursor/skills/exploratory-tester/SKILL.md +223 -0
- package/.cursor/skills/ios-customizer/SKILL.md +50 -15
- package/.cursor/skills/module-integrator/SKILL.md +2 -2
- package/.cursor/skills/output-validator/SKILL.md +1 -1
- package/.cursor/skills/react-native-customizer/SKILL.md +115 -25
- package/.cursor/skills/test-planner/SKILL.md +199 -0
- package/AGENTS.md +32 -11
- package/CLAUDE.md +78 -33
- package/README.md +77 -11
- package/designs/DESIGN_CATALOG.md +17 -15
- package/designs/DESIGN_PRINCIPLES.md +53 -0
- package/designs/brands/accessible-high-contrast.md +14 -0
- package/designs/brands/corporate-professional.md +14 -0
- package/designs/brands/dark-luxe.md +14 -0
- package/designs/brands/kids-playful.md +14 -0
- package/designs/brands/medical-clinical.md +14 -0
- package/designs/brands/modern-minimal.md +14 -0
- package/designs/brands/nature-organic.md +14 -0
- package/designs/brands/neo-brutalist.md +14 -0
- package/designs/brands/retro-vintage.md +14 -0
- package/designs/brands/soft-gradient.md +14 -0
- package/designs/brands/sport-athletic.md +14 -0
- package/designs/brands/tech-dynamic.md +14 -0
- package/designs/brands/vibrant-playful.md +14 -0
- package/dist/cli.d.ts +4 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +91 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/engines/claude-engine.d.ts.map +1 -1
- package/dist/engines/claude-engine.js +16 -4
- package/dist/engines/claude-engine.js.map +1 -1
- package/dist/engines/types.d.ts +1 -1
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/engines/types.js +31 -2
- package/dist/engines/types.js.map +1 -1
- package/dist/github.d.ts +3 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +47 -4
- package/dist/github.js.map +1 -1
- package/dist/index.js +217 -9
- package/dist/index.js.map +1 -1
- package/dist/prompt-builder.d.ts +11 -1
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js +216 -1
- package/dist/prompt-builder.js.map +1 -1
- package/dist/validator.d.ts +7 -2
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +61 -41
- package/dist/validator.js.map +1 -1
- package/dist/workspace.js +2 -2
- package/dist/workspace.js.map +1 -1
- package/package.json +2 -2
- package/prompts/agent-prompt.md +35 -18
- package/prompts/deep-test-agent-prompt.md +122 -0
- package/prompts/fix-agent-prompt.md +90 -0
- package/prompts/quick-agent-prompt.md +32 -2
- package/prompts/scratch-agent-prompt.md +5 -8
- package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/conversations/ConversationsScreen.kt +1 -1
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/navigation/MainScreen.kt +1 -0
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/navigation/MainNavigation.kt +5 -1
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/core/animation/MotionPreferencesScreen.kt +3 -3
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/navigation/Navigation.kt +1 -1
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/settings/SettingsScreen.kt +1 -1
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/features/settings/SettingsScreen.kt +3 -2
- package/templates/android/ReferenceTemplate/app/src/main/kotlin/com/appship/reference/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/ReferenceTemplate/app/src/main/kotlin/com/appship/reference/features/settings/SettingsScreen.kt +1 -1
- package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/features/cart/CartScreen.kt +3 -2
- package/templates/android/Skeleton/TESTING_MANIFEST.md +2 -1
- package/templates/android/Skeleton/app/src/main/kotlin/com/appship/skeleton/MainActivity.kt +23 -2
- package/templates/android/Skeleton/app/src/main/kotlin/com/appship/skeleton/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/Skeleton/app/src/main/kotlin/com/appship/skeleton/core/theme/AppearanceManager.kt +42 -0
- package/templates/android/Skeleton/app/src/main/kotlin/com/appship/skeleton/features/profile/ProfileScreen.kt +20 -8
- package/templates/android/Skeleton/tests/03_detail_screen.yaml +3 -2
- package/templates/android/Skeleton/tests/04_favorites.yaml +3 -2
- package/templates/android/Skeleton/tests/08_full_e2e.yaml +9 -2
- package/templates/android/Skeleton/tests/09_dark_mode.yaml +50 -0
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/settings/SettingsScreen.kt +3 -2
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/core/animation/AnimatedTransitionsModifiers.kt +188 -0
- package/templates/ios/BookTemplate/BookTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/ChatTemplate/ChatTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/DashTemplate/DashTemplate/App/AppConfig.swift +1 -0
- package/templates/ios/DashTemplate/DashTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/DashTemplate/DashTemplate/Core/Strings.swift +13 -0
- package/templates/ios/DashTemplate/DashTemplate.xcodeproj/project.pbxproj +32 -20
- package/templates/ios/FamilyTemplate/FamilyTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate/Core/Strings.swift +42 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate.xcodeproj/project.pbxproj +36 -30
- package/templates/ios/GameTemplate/GameTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/HealthTemplate/HealthTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/LearnTemplate/LearnTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/MapTemplate/MapTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/MediaTemplate/MediaTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/Core/Strings.swift +12 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/Features/SkeletonLoading/SkeletonLoadingView.swift +2 -37
- package/templates/ios/ShopTemplate/ShopTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/Skeleton/Skeleton/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/Skeleton/tests/08_full_e2e.yaml +4 -0
- package/templates/ios/Skeleton/tests/09_dark_mode.yaml +52 -0
- package/templates/ios/SocialTemplate/SocialTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/TaskTemplate/TaskTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/ios/TrackTemplate/TrackTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
- package/templates/react-native/BookTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/BookTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/BookTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/ChatTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/ChatTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/ChatTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/DashTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/DashTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/DashTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/FamilyTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/FamilyTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/FamilyTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/FinanceTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/FinanceTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/FinanceTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/GameTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/GameTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/GameTemplate/src/screens/GameDetail/GameDetailScreen.tsx +2 -1
- package/templates/react-native/GameTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/HealthTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/HealthTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/HealthTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/HealthTemplate/src/screens/WorkoutDetail/WorkoutDetailScreen.tsx +1 -1
- package/templates/react-native/LearnTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/LearnTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/LearnTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/MapTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/MapTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/MapTemplate/src/screens/Map/MapScreen.tsx +14 -0
- package/templates/react-native/MapTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/MediaTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/MediaTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/MediaTemplate/src/screens/PlaylistDetail/PlaylistDetailScreen.tsx +1 -1
- package/templates/react-native/MediaTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/ReferenceTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/ReferenceTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/ReferenceTemplate/src/screens/Settings/SettingsScreen.tsx +1 -1
- package/templates/react-native/ShopTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/ShopTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/ShopTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/Skeleton/TESTING_MANIFEST.md +2 -1
- package/templates/react-native/Skeleton/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/Skeleton/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/Skeleton/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/Skeleton/tests/07_profile.yaml +3 -2
- package/templates/react-native/Skeleton/tests/08_full_e2e.yaml +12 -1
- package/templates/react-native/Skeleton/tests/09_dark_mode.yaml +46 -0
- package/templates/react-native/SocialTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/SocialTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/SocialTemplate/src/screens/Feed/FeedScreen.tsx +1 -0
- package/templates/react-native/SocialTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/TaskTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/TaskTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/TaskTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
- package/templates/react-native/TrackTemplate/src/animation/useAnimatedList.ts +219 -2
- package/templates/react-native/TrackTemplate/src/animation/useMotionPreferences.ts +23 -9
- package/templates/react-native/TrackTemplate/src/screens/Settings/SettingsScreen.tsx +1 -1
- package/templates/shared/ios/AnimatedTransitions/AnimatedTransitionsView.swift +233 -93
- package/.claude/agents/template-selector.md +0 -39
- package/.claude/skills/module-selector/SKILL.md +0 -81
- package/.claude/skills/template-selector/SKILL.md +0 -44
- package/.cursor/agents/template-selector.md +0 -52
- package/.cursor/skills/module-selector/SKILL.md +0 -135
- package/.cursor/skills/template-selector/SKILL.md +0 -123
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exploratory-tester
|
|
3
|
+
description: Screenshot and accessibility-tree driven exploratory testing. Does NOT read source code — tests the app purely through what the AI sees on screen and what the accessibility tree reveals. Discovers visual bugs, accessibility issues, UX problems, and content issues that structured testing misses.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exploratory Tester Skill
|
|
7
|
+
|
|
8
|
+
Use this skill to test the app by exploring it visually — using screenshots and the accessibility/element tree as your only inputs. You do NOT read source code. You test what a real user would see and interact with.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- As Phase 2 of the `--deep-test` pipeline
|
|
13
|
+
- Runs in parallel with structured testing (Phase 3) on a separate simulator
|
|
14
|
+
- After the app is built and installed on a simulator
|
|
15
|
+
|
|
16
|
+
## Context You Need
|
|
17
|
+
|
|
18
|
+
- **Platform** — `ios`, `android`, or `react-native`
|
|
19
|
+
- **Bundle ID / Package name** — e.g., `com.pawspa.app`
|
|
20
|
+
- **Simulator/device name** — the `deviceName` for your assigned simulator
|
|
21
|
+
- **App directory** — path under `output/` (only for writing the bug report, NOT for reading code)
|
|
22
|
+
|
|
23
|
+
**IMPORTANT:** You must NOT read source code files (Views, ViewModels, Models, etc.). Your only inputs are what `inspect()` gives you — screenshots and the element tree. This forces you to test like a real user.
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
### Phase A — Screen Discovery
|
|
28
|
+
|
|
29
|
+
Start by launching the app and discovering all reachable screens:
|
|
30
|
+
|
|
31
|
+
1. **Launch the app:**
|
|
32
|
+
```
|
|
33
|
+
inspect({ platform: "{platform}", app: "{bundleId}", deviceName: "{sim}" })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
2. **Wait 3-5 seconds** for the app to fully render, then `inspect()` again.
|
|
37
|
+
|
|
38
|
+
3. **Map the tab bar** — identify all tabs from the element tree. Record their labels.
|
|
39
|
+
|
|
40
|
+
4. **Visit each tab** — tap each tab, `inspect()` on each to capture the screen and element tree.
|
|
41
|
+
|
|
42
|
+
5. **Discover sub-screens** — from each tab, tap list items, buttons, and links to discover detail screens, modals, forms. Keep a visited-screens list to avoid loops.
|
|
43
|
+
|
|
44
|
+
6. **Build a screen map:**
|
|
45
|
+
```
|
|
46
|
+
Tab 1 ("Home") → HomeScreen → DetailScreen (from list item)
|
|
47
|
+
Tab 2 ("Explore") → ExploreScreen → DetailScreen (from search result)
|
|
48
|
+
Tab 3 ("Favorites") → FavoritesScreen
|
|
49
|
+
Tab 4 ("Profile") → ProfileScreen → SettingsScreen
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Phase B — Per-Screen Exploratory Audit
|
|
53
|
+
|
|
54
|
+
For **each discovered screen**, perform the following audit:
|
|
55
|
+
|
|
56
|
+
#### B1 — Visual Analysis (from screenshot)
|
|
57
|
+
|
|
58
|
+
After each `inspect()`, analyze what you see:
|
|
59
|
+
|
|
60
|
+
- **Layout correctness:**
|
|
61
|
+
- No overlapping text or elements
|
|
62
|
+
- No cut-off labels or truncated content that loses meaning
|
|
63
|
+
- Proper spacing between elements (not cramped, not too sparse)
|
|
64
|
+
- Content aligned correctly (left-aligned text, centered headers, etc.)
|
|
65
|
+
- No elements extending beyond screen bounds
|
|
66
|
+
|
|
67
|
+
- **Content quality:**
|
|
68
|
+
- Real domain-specific text (not "Lorem ipsum", "Item 1", "Product", "Template")
|
|
69
|
+
- Images appear to be loaded (no broken image placeholders, no empty squares)
|
|
70
|
+
- Icons match their context (not generic or mismatched)
|
|
71
|
+
- Consistent typography across the screen
|
|
72
|
+
|
|
73
|
+
- **Design consistency:**
|
|
74
|
+
- Colors match between elements on the same screen
|
|
75
|
+
- Typography hierarchy makes sense (headers larger than body text)
|
|
76
|
+
- Consistent spacing and padding across similar elements
|
|
77
|
+
- Navigation bar style is consistent across screens
|
|
78
|
+
|
|
79
|
+
- **Template leftover detection:**
|
|
80
|
+
- Look for ANY generic text that doesn't match the app's domain
|
|
81
|
+
- Common leftovers: "ShopTemplate", "TrackTemplate", "SocialTemplate", "Template", "Example", "Sample", "Demo", "Test Item", "Lorem", "Placeholder"
|
|
82
|
+
- Check headers, list items, buttons, placeholders, empty state text
|
|
83
|
+
|
|
84
|
+
#### B2 — Accessibility Tree Audit
|
|
85
|
+
|
|
86
|
+
Parse the element tree from `inspect()` and audit:
|
|
87
|
+
|
|
88
|
+
- **Labels on interactive elements:**
|
|
89
|
+
- Every button must have a non-empty accessibility label
|
|
90
|
+
- Every link/tappable element must have a descriptive label
|
|
91
|
+
- Labels should describe the action, not just "button" or "element"
|
|
92
|
+
|
|
93
|
+
- **Image descriptions:**
|
|
94
|
+
- Images should have accessibility descriptions
|
|
95
|
+
- Decorative images can be marked as such, but content images need descriptions
|
|
96
|
+
|
|
97
|
+
- **Form field labels:**
|
|
98
|
+
- Text fields must have associated labels or placeholder text
|
|
99
|
+
- Pickers and selectors must be labeled
|
|
100
|
+
|
|
101
|
+
- **Orphaned elements:**
|
|
102
|
+
- Elements in the a11y tree that are not visible on screen (hidden but accessible)
|
|
103
|
+
- Elements visible on screen but not in the a11y tree (visible but not accessible)
|
|
104
|
+
|
|
105
|
+
- **Touch target sizes:**
|
|
106
|
+
- Interactive elements should be at least 44x44pt (iOS) or 48x48dp (Android)
|
|
107
|
+
- Flag any buttons or tappable elements that appear too small
|
|
108
|
+
|
|
109
|
+
#### B3 — Interactive Exploration
|
|
110
|
+
|
|
111
|
+
Interact with EVERY discoverable element and observe what happens:
|
|
112
|
+
|
|
113
|
+
1. **Tap every button** — verify something happens (navigation, modal, state change, animation). Record any buttons that do nothing ("dead buttons").
|
|
114
|
+
|
|
115
|
+
2. **Type into every text field:**
|
|
116
|
+
- Normal text: verify it appears correctly
|
|
117
|
+
- Edge cases: empty submit, very long text (50+ characters), special characters (@#$%)
|
|
118
|
+
- Search fields: type a query and verify results update
|
|
119
|
+
|
|
120
|
+
3. **Toggle every switch/checkbox** — verify state changes visually.
|
|
121
|
+
|
|
122
|
+
4. **Scroll every list:**
|
|
123
|
+
- Scroll to the bottom — verify all items render
|
|
124
|
+
- Scroll back to the top — verify the header/nav bar is intact (no overlap bugs)
|
|
125
|
+
|
|
126
|
+
5. **Try unexpected interactions:**
|
|
127
|
+
- Swipe on non-swipeable areas — should not cause crashes or weird behavior
|
|
128
|
+
- Double-tap buttons — should not trigger the action twice (unless intentional)
|
|
129
|
+
- Tap on non-interactive text — should not crash
|
|
130
|
+
|
|
131
|
+
6. **Test navigation depth:**
|
|
132
|
+
- Navigate 3+ levels deep (tab → list item → detail → sub-detail)
|
|
133
|
+
- Navigate back all the way — verify each screen restores correctly
|
|
134
|
+
- Verify the back button works at every level
|
|
135
|
+
|
|
136
|
+
7. **Test state persistence:**
|
|
137
|
+
- Toggle a favorite, navigate away, come back — is it still toggled?
|
|
138
|
+
- Enter text in a form, switch tabs, come back — is the text preserved?
|
|
139
|
+
- Scroll down in a list, switch tabs, come back — is the scroll position preserved?
|
|
140
|
+
|
|
141
|
+
8. **Test tab switching:**
|
|
142
|
+
- Switch between all tabs rapidly
|
|
143
|
+
- Verify each tab shows its correct content (not stale data from another tab)
|
|
144
|
+
- Verify the selected tab indicator updates correctly
|
|
145
|
+
|
|
146
|
+
#### B4 — After-Interaction Comparison
|
|
147
|
+
|
|
148
|
+
After completing interactions on a screen:
|
|
149
|
+
|
|
150
|
+
1. `inspect()` again to capture the post-interaction state
|
|
151
|
+
2. Compare the element tree with the pre-interaction tree
|
|
152
|
+
3. Flag any unexpected changes:
|
|
153
|
+
- Elements that disappeared when they shouldn't have
|
|
154
|
+
- New elements that appeared unexpectedly
|
|
155
|
+
- Element labels that changed incorrectly
|
|
156
|
+
- Count mismatches (e.g., list had 5 items, now has 4)
|
|
157
|
+
|
|
158
|
+
### Phase C — Bug Classification and Reporting
|
|
159
|
+
|
|
160
|
+
For each issue discovered, classify it:
|
|
161
|
+
|
|
162
|
+
| Tag | Category | Description | Severity Guide |
|
|
163
|
+
|-----|----------|-------------|----------------|
|
|
164
|
+
| `[VISUAL]` | Visual | Layout, overlap, truncation, wrong colors | Medium if minor, High if content is unreadable |
|
|
165
|
+
| `[A11Y]` | Accessibility | Missing labels, unreachable elements, small targets | Medium for labels, High for unreachable elements |
|
|
166
|
+
| `[UX]` | User Experience | Dead buttons, confusing navigation, unexpected behavior | High for dead buttons, Medium for confusing flows |
|
|
167
|
+
| `[CONTENT]` | Content | Template leftovers, placeholder text, wrong domain text | High for template leftovers, Medium for placeholders |
|
|
168
|
+
| `[STATE]` | State | State not updating, data not persisting, stale views | High for data loss, Medium for stale views |
|
|
169
|
+
| `[CRASH]` | Crash | App crashes on interaction | Critical (P0) |
|
|
170
|
+
|
|
171
|
+
Format each bug as:
|
|
172
|
+
|
|
173
|
+
```markdown
|
|
174
|
+
### BUG-{NNN}: [{SEVERITY}][EXPLORATORY][{TAG}] {Short description}
|
|
175
|
+
- **Screen:** {screen name}
|
|
176
|
+
- **Element:** {element description from a11y tree}
|
|
177
|
+
- **Steps to reproduce:** {what you tapped/typed/swiped}
|
|
178
|
+
- **Expected:** {what should happen}
|
|
179
|
+
- **Actual:** {what actually happened}
|
|
180
|
+
- **Screenshot context:** {brief description of what the screenshot showed}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Phase D — Write Bug Report Section
|
|
184
|
+
|
|
185
|
+
Append your findings to `output/{app-name}/reports/11-bug-report.md`. If the file doesn't exist, create it. Use this structure:
|
|
186
|
+
|
|
187
|
+
```markdown
|
|
188
|
+
# Bug Report — Exploratory Testing
|
|
189
|
+
|
|
190
|
+
## Summary
|
|
191
|
+
- Screens discovered: {N}
|
|
192
|
+
- Screens audited: {N}
|
|
193
|
+
- Total interactive elements found: {N}
|
|
194
|
+
- Total interactions performed: {N}
|
|
195
|
+
- Bugs found: {N}
|
|
196
|
+
- Critical (P0): {N}
|
|
197
|
+
- High (P1): {N}
|
|
198
|
+
- Medium (P2): {N}
|
|
199
|
+
- Low (P3): {N}
|
|
200
|
+
|
|
201
|
+
## Accessibility Summary
|
|
202
|
+
- Elements with labels: {N}/{total}
|
|
203
|
+
- Elements missing labels: {N}
|
|
204
|
+
- Images with descriptions: {N}/{total}
|
|
205
|
+
- Touch targets below minimum: {N}
|
|
206
|
+
|
|
207
|
+
## Screen Map
|
|
208
|
+
{screen discovery tree from Phase A}
|
|
209
|
+
|
|
210
|
+
## Bugs
|
|
211
|
+
{all bugs from Phase C}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Important Rules
|
|
215
|
+
|
|
216
|
+
- **DO NOT read source code** — your inputs are ONLY screenshots and the element tree from `inspect()`
|
|
217
|
+
- **DO NOT follow a test plan** — explore freely based on what you see
|
|
218
|
+
- **Test EVERY interactive element** you discover in the element tree
|
|
219
|
+
- Use ai-tester MCP tools (`inspect`, `act`, `assert`, `wait`) for ALL interaction — NOT shell commands
|
|
220
|
+
- If the app crashes, document it as a P0/Critical bug and try to restart
|
|
221
|
+
- You are testing on a SINGLE assigned simulator — use the provided `deviceName` in all MCP calls
|
|
222
|
+
- Write your findings to the bug report — do NOT fix bugs (that's the bug-fixer skill's job)
|
|
223
|
+
- Be thorough: an element tree with 20 buttons means you tap all 20 buttons
|
|
@@ -9,7 +9,7 @@ Use this skill to perform deep iOS/SwiftUI customization on a cloned template.
|
|
|
9
9
|
|
|
10
10
|
## When to Use
|
|
11
11
|
|
|
12
|
-
- At Step
|
|
12
|
+
- At Step 5 of the AppAgent workflow, when the platform is iOS
|
|
13
13
|
- After AppConfig, mock data, and design tokens are already in place
|
|
14
14
|
- When you need to modify SwiftUI views, navigation, and themes
|
|
15
15
|
|
|
@@ -100,7 +100,21 @@ iOS templates use a `Colors.swift` theme file:
|
|
|
100
100
|
- Use semantic colors where possible (`Color.primary`, `Color.secondary`)
|
|
101
101
|
- Apply corner radius and spacing tokens from the design brief
|
|
102
102
|
|
|
103
|
-
### Step 4.5 —
|
|
103
|
+
### Step 4.5 — Visual Polish Application
|
|
104
|
+
|
|
105
|
+
Apply the **Visual Polish Plan** from the customization manifest. This step is MANDATORY for every build — it makes apps feel handcrafted rather than template-like.
|
|
106
|
+
|
|
107
|
+
1. **Shadows**: Apply `.cardShadow()` to every card, list item card, and elevated surface. Use `.elevatedShadow()` for FABs and floating buttons. If no `.cardShadow()` modifier exists, add `shadow(color:radius:x:y:)` directly using the manifest's shadow tokens.
|
|
108
|
+
2. **Gradients**: Apply `LinearGradient` to hero sections (detail screen headers, banner areas) and primary CTA buttons per the manifest's gradient usage plan. Use `Color.appPrimary` → `Color.appSecondary` for primary gradient.
|
|
109
|
+
3. **Press feedback**: Ensure all `Button` and tappable elements use `.scaleOnPress()` or `ButtonStyle` with scale animation (scale to 0.95 on press, spring return). For key interactions (favorite toggle, submit), add `UIImpactFeedbackGenerator(style: .light).impactOccurred()`.
|
|
110
|
+
4. **Staggered animations**: Ensure all `ForEach` / `LazyVStack` list views apply `.staggeredAppear(index:)` to each item. This gives lists a lively cascading entrance.
|
|
111
|
+
5. **Empty states**: Enhance empty state views — add a gradient circle background behind the icon (e.g., `Circle().fill(LinearGradient(...)).frame(width: 80, height: 80)` behind the SF Symbol), and add `.slideIn()` animation to the entire empty state composition.
|
|
112
|
+
6. **Glass/blur**: Apply `.ultraThinMaterial` or `.regularMaterial` to sheet backgrounds and overlay views. Use `.background(.ultraThinMaterial)` on navigation bars where appropriate.
|
|
113
|
+
7. **Haptic feedback**: Add `UIImpactFeedbackGenerator` calls to favorite toggles, pull-to-refresh completions, and primary action buttons.
|
|
114
|
+
|
|
115
|
+
Verify visual hierarchy: hero elements (large images, gradients) stand out > section headers > cards (with shadows) > inline text.
|
|
116
|
+
|
|
117
|
+
### Step 4.6 — Generate App Launcher Icon
|
|
104
118
|
|
|
105
119
|
Generate a domain-specific app icon using the manifest's **App Launcher Icon** section:
|
|
106
120
|
|
|
@@ -229,26 +243,47 @@ If the customization manifest includes an **"Animation & Sensory Plan"** section
|
|
|
229
243
|
3. **Apply the modifiers** using the imported module code:
|
|
230
244
|
|
|
231
245
|
```swift
|
|
232
|
-
//
|
|
246
|
+
// Built-in press feedback (always available)
|
|
233
247
|
Button("Add to Cart") { ... }
|
|
234
248
|
.scaleOnPress()
|
|
235
|
-
.hapticFeedback(.
|
|
249
|
+
.hapticFeedback(.medium)
|
|
250
|
+
|
|
251
|
+
// Built-in staggered list items (always available)
|
|
252
|
+
ForEach(items.indices, id: \.self) { index in
|
|
253
|
+
ItemRow(item: items[index])
|
|
254
|
+
.staggeredAppear(index: index)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Built-in shadow (always available)
|
|
258
|
+
CardView(item: item)
|
|
259
|
+
.cardShadow()
|
|
236
260
|
|
|
237
|
-
//
|
|
261
|
+
// Built-in slide animation (always available)
|
|
262
|
+
EmptyStateView()
|
|
263
|
+
.slideIn()
|
|
264
|
+
|
|
265
|
+
// Built-in shimmer for loading placeholders (always available)
|
|
266
|
+
RoundedRectangle(cornerRadius: 8)
|
|
267
|
+
.fill(Color(.systemGray5))
|
|
268
|
+
.frame(height: 60)
|
|
269
|
+
.shimmer()
|
|
270
|
+
|
|
271
|
+
// Built-in pulse for live indicators (always available)
|
|
272
|
+
Circle().fill(.red).frame(width: 8, height: 8)
|
|
273
|
+
.pulse()
|
|
274
|
+
|
|
275
|
+
// Built-in heart bounce for favorites (always available)
|
|
276
|
+
Image(systemName: isFavorite ? "heart.fill" : "heart")
|
|
277
|
+
.heartBounce(isActive: isFavorite)
|
|
278
|
+
|
|
279
|
+
// ScrollEffects module — parallax header (if module integrated)
|
|
238
280
|
ScrollView {
|
|
239
281
|
ParallaxHeaderView(height: 280) {
|
|
240
282
|
AsyncImage(url: item.imageURL)
|
|
241
283
|
}
|
|
242
|
-
// content below
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// AnimatedTransitions — staggered list items
|
|
246
|
-
ForEach(items.indices, id: \.self) { index in
|
|
247
|
-
ItemRow(item: items[index])
|
|
248
|
-
.staggeredAppearance(index: index)
|
|
249
284
|
}
|
|
250
285
|
|
|
251
|
-
// CelebrationEffects — success overlay
|
|
286
|
+
// CelebrationEffects module — success overlay (if module integrated)
|
|
252
287
|
.celebrationOverlay(isPresented: $showCelebration, style: .confetti)
|
|
253
288
|
```
|
|
254
289
|
|
|
@@ -262,7 +297,7 @@ Write the report to `output/{app-name}/reports/05-customization.md` (append iOS
|
|
|
262
297
|
```markdown
|
|
263
298
|
# Customization Report
|
|
264
299
|
|
|
265
|
-
**Step:**
|
|
300
|
+
**Step:** 5
|
|
266
301
|
**Skill:** ios-customizer
|
|
267
302
|
**Timestamp:** {ISO 8601}
|
|
268
303
|
**Result:** PASS
|
|
@@ -312,7 +347,7 @@ Update `output/{app-name}/reports/summary.json` — read the file, append this s
|
|
|
312
347
|
|
|
313
348
|
```json
|
|
314
349
|
{
|
|
315
|
-
"step":
|
|
350
|
+
"step": 5,
|
|
316
351
|
"name": "ios-customization",
|
|
317
352
|
"startedAt": "{ISO 8601 timestamp}",
|
|
318
353
|
"durationSeconds": 0,
|
|
@@ -9,7 +9,7 @@ Integrate selected shared modules into the app by reading their reference implem
|
|
|
9
9
|
|
|
10
10
|
## Context You Need
|
|
11
11
|
|
|
12
|
-
- **
|
|
12
|
+
- **Catalog analysis report** — `output/{app-name}/reports/02-catalog-analysis.md` — lists which template and modules were selected
|
|
13
13
|
- **Customization manifest** — `output/{app-name}/reports/customization-manifest.md` — contains the module integration plan with placement decisions
|
|
14
14
|
- **Platform** — `ios` or `android`
|
|
15
15
|
- **App name and bundle ID** — for adapting imports and identifiers
|
|
@@ -19,7 +19,7 @@ Integrate selected shared modules into the app by reading their reference implem
|
|
|
19
19
|
|
|
20
20
|
### Step 1 — Read the Module Selection Report
|
|
21
21
|
|
|
22
|
-
Read `output/{app-name}/reports/
|
|
22
|
+
Read the "Module Selection" section from `output/{app-name}/reports/02-catalog-analysis.md` to get the list of selected modules. Read the "Module Integration Plan" section from the customization manifest to understand where each module connects.
|
|
23
23
|
|
|
24
24
|
### Step 2 — For Each Selected Module, Integrate It
|
|
25
25
|
|
|
@@ -101,7 +101,7 @@ Mark all animation issues as `[WARN]` — they affect quality but are not build-
|
|
|
101
101
|
|
|
102
102
|
Verify that the reports directory has the expected files:
|
|
103
103
|
- `01-prompt-validation.md` exists
|
|
104
|
-
- `02-
|
|
104
|
+
- `02-catalog-analysis.md` exists
|
|
105
105
|
- `03-design-brand.md` exists
|
|
106
106
|
- `04-content-brief.md` exists
|
|
107
107
|
- `05-customization.md` exists
|
|
@@ -133,12 +133,29 @@ const lightColors = {
|
|
|
133
133
|
};
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
### Step 5 —
|
|
136
|
+
### Step 4.5 — Visual Polish Application
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
Apply the **Visual Polish Plan** from the customization manifest. This step is MANDATORY — it makes apps feel handcrafted rather than template-like.
|
|
139
|
+
|
|
140
|
+
1. **Shadows**: Apply shadow styles to every card and elevated surface. Use platform-aware styles: `shadowColor`, `shadowOffset`, `shadowOpacity`, `shadowRadius` (iOS) and `elevation` (Android). Create a `cardShadow` style object and spread it into card `StyleSheet` definitions.
|
|
141
|
+
2. **Gradients**: Use `expo-linear-gradient` `LinearGradient` component for hero sections (detail screen headers, banner areas) and primary CTA buttons. Apply `colors={[colors.primary, colors.secondary]}` with `start/end` props for direction.
|
|
142
|
+
3. **Press feedback**: Ensure all `TouchableOpacity` elements use `activeOpacity={0.85}` and add a scale animation on press using `Animated.spring()` (scale to 0.95, spring back). Wrap common buttons in a `ScaleButton` component.
|
|
143
|
+
4. **Staggered animations**: Ensure all `FlatList` items use `useStaggeredAppear(index)` hook for animated entrance. Apply the returned `animatedStyle` to each item's `Animated.View` wrapper.
|
|
144
|
+
5. **Empty states**: Enhance empty state components — add a gradient circle background behind the icon (using `LinearGradient` + `borderRadius: 40`), and add slide-in animation with `useSlideIn()`.
|
|
145
|
+
6. **Blur/glass**: Use `expo-blur` `BlurView` for modal/sheet backgrounds where supported. Fall back to semi-transparent background.
|
|
146
|
+
7. **Haptic feedback**: Use `expo-haptics` or React Native `Vibration` API on favorite toggles and primary actions.
|
|
147
|
+
|
|
148
|
+
Verify visual hierarchy: hero elements > section headers > cards (with shadows) > inline text.
|
|
149
|
+
|
|
150
|
+
### Step 5 — Data Layer & Offline Infrastructure
|
|
151
|
+
|
|
152
|
+
Templates include an **offline-first data layer**. Understand these components:
|
|
139
153
|
|
|
140
154
|
**Files you should NOT modify** (generic infrastructure):
|
|
141
155
|
- `src/data/DataRepository.ts` — interface definition
|
|
156
|
+
- `src/data/NetworkMonitor.ts` — connectivity detection
|
|
157
|
+
- `src/data/LocalPersistence.ts` — JSON file persistence
|
|
158
|
+
- `src/components/OfflineBanner.tsx` — offline status banner
|
|
142
159
|
- `src/theme/ThemeContext.tsx` — theme provider
|
|
143
160
|
|
|
144
161
|
**Files you MAY need to update** (domain-specific):
|
|
@@ -147,25 +164,29 @@ Templates use a `MockDataProvider.ts` that implements `DataRepository` interface
|
|
|
147
164
|
- All CRUD methods work with correct entity types
|
|
148
165
|
- Subscription/onChange pattern is working
|
|
149
166
|
- Reset method references correct defaults
|
|
167
|
+
- `src/data/SyncManager.ts` — if entity types were renamed, update domain methods
|
|
150
168
|
|
|
151
169
|
**ViewModel patterns** (how screens consume data):
|
|
152
170
|
|
|
153
|
-
ViewModels are custom React hooks that use MockDataProvider:
|
|
171
|
+
ViewModels are custom React hooks that use the `DataRepository` interface via `DataSourceResolver`, not `MockDataProvider` directly:
|
|
154
172
|
```tsx
|
|
173
|
+
import { DataSourceResolver } from '../data/DataSourceResolver';
|
|
174
|
+
|
|
155
175
|
export function useHomeViewModel() {
|
|
176
|
+
const repository = DataSourceResolver.repository;
|
|
156
177
|
const [items, setItems] = useState<Item[]>([]);
|
|
157
178
|
const [isLoading, setIsLoading] = useState(true);
|
|
158
179
|
|
|
159
180
|
useEffect(() => {
|
|
160
181
|
loadData();
|
|
161
|
-
const unsubscribe =
|
|
162
|
-
setItems(
|
|
182
|
+
const unsubscribe = repository.subscribe(() => {
|
|
183
|
+
setItems(repository.getItems());
|
|
163
184
|
});
|
|
164
185
|
return unsubscribe;
|
|
165
186
|
}, []);
|
|
166
187
|
|
|
167
188
|
const loadData = () => {
|
|
168
|
-
setItems(
|
|
189
|
+
setItems(repository.getItems());
|
|
169
190
|
setIsLoading(false);
|
|
170
191
|
};
|
|
171
192
|
|
|
@@ -173,6 +194,16 @@ export function useHomeViewModel() {
|
|
|
173
194
|
}
|
|
174
195
|
```
|
|
175
196
|
|
|
197
|
+
When customizing ViewModels, ALWAYS use `DataSourceResolver.repository`, never `MockDataProvider` directly. This ensures the app works with any data source (mock, localStorage, Firebase, Supabase, custom API).
|
|
198
|
+
|
|
199
|
+
**OfflineBanner integration** — add to main navigation screens:
|
|
200
|
+
```tsx
|
|
201
|
+
<View style={{ flex: 1 }}>
|
|
202
|
+
<OfflineBanner />
|
|
203
|
+
{/* ... rest of screen content */}
|
|
204
|
+
</View>
|
|
205
|
+
```
|
|
206
|
+
|
|
176
207
|
### Step 6 — Data Layer Verification
|
|
177
208
|
|
|
178
209
|
Verify the data layer uses correct patterns:
|
|
@@ -193,9 +224,36 @@ export interface DataRepository {
|
|
|
193
224
|
}
|
|
194
225
|
```
|
|
195
226
|
|
|
227
|
+
**MockDataProvider (implements DataRepository):**
|
|
228
|
+
```tsx
|
|
229
|
+
class MockDataProvider implements DataRepository {
|
|
230
|
+
private static instance: MockDataProvider;
|
|
231
|
+
private listeners: Set<() => void> = new Set();
|
|
232
|
+
|
|
233
|
+
getItems(): Item[] { ... }
|
|
234
|
+
addItem(item: Item): void { ... }
|
|
235
|
+
subscribe(callback: () => void): () => void { ... }
|
|
236
|
+
reset(): void { ... } // Reset to defaults
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**DataSourceResolver:**
|
|
241
|
+
```tsx
|
|
242
|
+
export class DataSourceResolver {
|
|
243
|
+
static get repository(): DataRepository {
|
|
244
|
+
switch (AppConfig.DataSource.active) {
|
|
245
|
+
case 'localStorage': return MockDataProvider.getInstance(); // TODO: LocalStorageProvider
|
|
246
|
+
case 'mock': return MockDataProvider.getInstance();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
196
252
|
Verify:
|
|
197
|
-
-
|
|
198
|
-
-
|
|
253
|
+
- DataRepository interface matches MockDataProvider's public methods
|
|
254
|
+
- MockDataProvider implements DataRepository
|
|
255
|
+
- DataSourceResolver returns the correct implementation
|
|
256
|
+
- ViewModel hooks use `DataSourceResolver.repository`, not `MockDataProvider` directly
|
|
199
257
|
- Seed data matches the new domain
|
|
200
258
|
- CRUD methods reference correct entity types
|
|
201
259
|
|
|
@@ -208,35 +266,59 @@ If the customization manifest includes an **"Animation & Sensory Plan"** section
|
|
|
208
266
|
3. **Apply the modifiers** using the imported module hooks/components:
|
|
209
267
|
|
|
210
268
|
```typescript
|
|
211
|
-
//
|
|
212
|
-
import { useScaleOnPress,
|
|
213
|
-
import { useHapticEngine } from '../shared/HapticEngine';
|
|
214
|
-
|
|
215
|
-
const { animatedStyle, handlers } = useScaleOnPress();
|
|
216
|
-
const haptic = useHapticEngine();
|
|
269
|
+
// Built-in hooks (always available in animation/useAnimatedList)
|
|
270
|
+
import { useScaleOnPress, useStaggeredAppear, useSlideIn, cardShadowStyle, useShimmer, usePulse, useHeartBounce } from '../animation/useAnimatedList';
|
|
217
271
|
|
|
218
|
-
|
|
219
|
-
|
|
272
|
+
// Press feedback
|
|
273
|
+
const { style: pressStyle, onPressIn, onPressOut } = useScaleOnPress();
|
|
274
|
+
<Animated.View style={pressStyle}>
|
|
275
|
+
<Pressable onPressIn={onPressIn} onPressOut={onPressOut} onPress={doAction}>
|
|
220
276
|
<Text>Add to Cart</Text>
|
|
221
|
-
</
|
|
277
|
+
</Pressable>
|
|
222
278
|
</Animated.View>
|
|
223
279
|
|
|
224
|
-
//
|
|
225
|
-
|
|
280
|
+
// Staggered list items
|
|
281
|
+
const animStyle = useStaggeredAppear(index);
|
|
282
|
+
<Animated.View style={animStyle}><ItemCard item={item} /></Animated.View>
|
|
226
283
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
</ParallaxHeader>
|
|
284
|
+
// Card shadow
|
|
285
|
+
<View style={[styles.card, cardShadowStyle()]}>{/* content */}</View>
|
|
230
286
|
|
|
231
|
-
//
|
|
232
|
-
|
|
287
|
+
// Slide-in animation
|
|
288
|
+
const slideStyle = useSlideIn();
|
|
289
|
+
<Animated.View style={slideStyle}><EmptyState /></Animated.View>
|
|
233
290
|
|
|
291
|
+
// Shimmer for loading placeholders
|
|
292
|
+
const shimmerStyle = useShimmer();
|
|
293
|
+
<Animated.View style={[styles.placeholder, shimmerStyle]} />
|
|
294
|
+
|
|
295
|
+
// Pulse for live indicators
|
|
296
|
+
const pulseStyle = usePulse();
|
|
297
|
+
<Animated.View style={[styles.dot, pulseStyle]} />
|
|
298
|
+
|
|
299
|
+
// Heart bounce for favorite toggles
|
|
300
|
+
const heartStyle = useHeartBounce(isFavorite);
|
|
301
|
+
<Animated.View style={heartStyle}><HeartIcon /></Animated.View>
|
|
302
|
+
|
|
303
|
+
// Modules (if integrated)
|
|
304
|
+
import { ParallaxHeader } from '../shared/ScrollEffects';
|
|
305
|
+
<ParallaxHeader height={280} imageSource={item.imageUrl} />
|
|
306
|
+
|
|
307
|
+
import { CelebrationOverlay } from '../shared/CelebrationEffects';
|
|
234
308
|
<CelebrationOverlay isActive={showCelebration} style="confetti" />
|
|
235
309
|
```
|
|
236
310
|
|
|
237
311
|
4. **Wrap all applied animations** with `useMotionPreferences` checks if MotionPreferences is integrated
|
|
238
312
|
5. **Do NOT add animation modifiers** to screens not listed in the manifest
|
|
239
313
|
|
|
314
|
+
### Step 6.7 — App Icon (if applicable)
|
|
315
|
+
|
|
316
|
+
React Native apps target both iOS and Android. App icon customization is handled per-platform:
|
|
317
|
+
- **iOS**: If `scripts/generate-app-icon.swift` exists, run it with the SF Symbol and background color from the manifest
|
|
318
|
+
- **Android**: If `templates/android/ICON_VECTORS.md` exists, update `android/app/src/main/res/drawable/ic_launcher_foreground.xml` and `ic_launcher_background` color
|
|
319
|
+
|
|
320
|
+
If the scripts/resources are not available, skip — the template's default icons will be used.
|
|
321
|
+
|
|
240
322
|
## Report Output
|
|
241
323
|
|
|
242
324
|
Write the report to `output/{app-name}/reports/05-customization.md`:
|
|
@@ -269,6 +351,12 @@ React Native (TypeScript)
|
|
|
269
351
|
- Empty states: {count}
|
|
270
352
|
- CTAs updated: {count}
|
|
271
353
|
|
|
354
|
+
## Offline Infrastructure
|
|
355
|
+
|
|
356
|
+
- OfflineBanner integrated: {yes/no}
|
|
357
|
+
- SyncManager methods updated: {list or "no changes needed"}
|
|
358
|
+
- Data persistence verified: {yes/no}
|
|
359
|
+
|
|
272
360
|
## Animation Modifiers Applied
|
|
273
361
|
|
|
274
362
|
- {modifier}: applied to {screen} — {description}
|
|
@@ -324,8 +412,10 @@ Templates include `testID` props on all interactive elements and a `TESTING_MANI
|
|
|
324
412
|
- ONLY edit files under `output/` — never touch `templates/`
|
|
325
413
|
- Ensure all imports resolve after your changes
|
|
326
414
|
- Preserve `MockDataProvider` CRUD methods and `reset()` function
|
|
415
|
+
- Do NOT modify NetworkMonitor, LocalPersistence, or OfflineBanner
|
|
416
|
+
- Ensure OfflineBanner is integrated into main navigation screens
|
|
327
417
|
- Use `testID` props on ALL interactive elements
|
|
328
|
-
- Follow `{screen}_{element}_{role}` convention for new test IDs
|
|
418
|
+
- Follow `{screen}_{element}_{role}` convention for new test IDs (see `templates/TEST_ID_CONVENTIONS.md`)
|
|
329
419
|
- Use `StyleSheet.create()` for styles, not inline objects
|
|
330
420
|
- Use functional components with TypeScript
|
|
331
421
|
- Keep React Navigation structure intact
|