tribunal-kit 2.4.6 → 3.1.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/.agent/ARCHITECTURE.md +99 -99
- package/.agent/GEMINI.md +52 -52
- package/.agent/agents/accessibility-reviewer.md +139 -86
- package/.agent/agents/ai-code-reviewer.md +160 -90
- package/.agent/agents/backend-specialist.md +164 -127
- package/.agent/agents/code-archaeologist.md +115 -73
- package/.agent/agents/database-architect.md +130 -110
- package/.agent/agents/debugger.md +137 -97
- package/.agent/agents/dependency-reviewer.md +78 -30
- package/.agent/agents/devops-engineer.md +161 -118
- package/.agent/agents/documentation-writer.md +151 -87
- package/.agent/agents/explorer-agent.md +117 -99
- package/.agent/agents/frontend-reviewer.md +127 -47
- package/.agent/agents/frontend-specialist.md +169 -109
- package/.agent/agents/game-developer.md +28 -164
- package/.agent/agents/logic-reviewer.md +87 -49
- package/.agent/agents/mobile-developer.md +151 -103
- package/.agent/agents/mobile-reviewer.md +133 -50
- package/.agent/agents/orchestrator.md +121 -110
- package/.agent/agents/penetration-tester.md +103 -77
- package/.agent/agents/performance-optimizer.md +136 -92
- package/.agent/agents/performance-reviewer.md +139 -69
- package/.agent/agents/product-manager.md +104 -70
- package/.agent/agents/product-owner.md +6 -25
- package/.agent/agents/project-planner.md +95 -95
- package/.agent/agents/qa-automation-engineer.md +174 -87
- package/.agent/agents/security-auditor.md +133 -129
- package/.agent/agents/seo-specialist.md +160 -99
- package/.agent/agents/sql-reviewer.md +132 -44
- package/.agent/agents/supervisor-agent.md +137 -109
- package/.agent/agents/swarm-worker-contracts.md +17 -17
- package/.agent/agents/swarm-worker-registry.md +46 -46
- package/.agent/agents/test-coverage-reviewer.md +132 -53
- package/.agent/agents/test-engineer.md +0 -21
- package/.agent/agents/type-safety-reviewer.md +143 -33
- package/.agent/patterns/generator.md +9 -9
- package/.agent/patterns/inversion.md +12 -12
- package/.agent/patterns/pipeline.md +9 -9
- package/.agent/patterns/reviewer.md +13 -13
- package/.agent/patterns/tool-wrapper.md +9 -9
- package/.agent/rules/GEMINI.md +63 -63
- package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
- package/.agent/scripts/compress_skills.py +167 -0
- package/.agent/scripts/consolidate_skills.py +173 -0
- package/.agent/scripts/deep_compress.py +202 -0
- package/.agent/scripts/minify_context.py +80 -0
- package/.agent/scripts/security_scan.py +1 -1
- package/.agent/scripts/strip_tribunal.py +41 -0
- package/.agent/skills/agent-organizer/SKILL.md +60 -100
- package/.agent/skills/agentic-patterns/SKILL.md +0 -70
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +108 -53
- package/.agent/skills/api-patterns/SKILL.md +197 -257
- package/.agent/skills/api-security-auditor/SKILL.md +125 -57
- package/.agent/skills/app-builder/SKILL.md +326 -50
- package/.agent/skills/app-builder/templates/SKILL.md +13 -15
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +16 -16
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +22 -22
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +20 -20
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +17 -17
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +21 -21
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +20 -20
- package/.agent/skills/appflow-wireframe/SKILL.md +71 -98
- package/.agent/skills/architecture/SKILL.md +161 -200
- package/.agent/skills/authentication-best-practices/SKILL.md +121 -54
- package/.agent/skills/bash-linux/SKILL.md +71 -166
- package/.agent/skills/behavioral-modes/SKILL.md +8 -69
- package/.agent/skills/brainstorming/SKILL.md +345 -127
- package/.agent/skills/building-native-ui/SKILL.md +125 -57
- package/.agent/skills/clean-code/SKILL.md +266 -149
- package/.agent/skills/code-review-checklist/SKILL.md +0 -62
- package/.agent/skills/config-validator/SKILL.md +73 -131
- package/.agent/skills/csharp-developer/SKILL.md +434 -73
- package/.agent/skills/database-design/SKILL.md +190 -275
- package/.agent/skills/deployment-procedures/SKILL.md +81 -158
- package/.agent/skills/devops-engineer/SKILL.md +255 -94
- package/.agent/skills/devops-incident-responder/SKILL.md +50 -69
- package/.agent/skills/doc.md +5 -5
- package/.agent/skills/documentation-templates/SKILL.md +19 -63
- package/.agent/skills/edge-computing/SKILL.md +75 -165
- package/.agent/skills/extract-design-system/SKILL.md +84 -58
- package/.agent/skills/framer-motion-expert/SKILL.md +195 -0
- package/.agent/skills/frontend-design/SKILL.md +151 -499
- package/.agent/skills/game-design-expert/SKILL.md +71 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +88 -0
- package/.agent/skills/geo-fundamentals/SKILL.md +52 -178
- package/.agent/skills/github-operations/SKILL.md +197 -272
- package/.agent/skills/gsap-expert/SKILL.md +194 -0
- package/.agent/skills/i18n-localization/SKILL.md +60 -172
- package/.agent/skills/intelligent-routing/SKILL.md +123 -103
- package/.agent/skills/lint-and-validate/SKILL.md +8 -52
- package/.agent/skills/llm-engineering/SKILL.md +281 -195
- package/.agent/skills/local-first/SKILL.md +76 -159
- package/.agent/skills/mcp-builder/SKILL.md +48 -188
- package/.agent/skills/mobile-design/SKILL.md +213 -219
- package/.agent/skills/motion-engineering/SKILL.md +184 -0
- package/.agent/skills/nextjs-react-expert/SKILL.md +184 -203
- package/.agent/skills/nodejs-best-practices/SKILL.md +403 -185
- package/.agent/skills/observability/SKILL.md +211 -203
- package/.agent/skills/parallel-agents/SKILL.md +53 -146
- package/.agent/skills/performance-profiling/SKILL.md +171 -151
- package/.agent/skills/plan-writing/SKILL.md +49 -153
- package/.agent/skills/platform-engineer/SKILL.md +57 -103
- package/.agent/skills/playwright-best-practices/SKILL.md +110 -63
- package/.agent/skills/powershell-windows/SKILL.md +61 -179
- package/.agent/skills/python-patterns/SKILL.md +7 -35
- package/.agent/skills/python-pro/SKILL.md +273 -114
- package/.agent/skills/react-specialist/SKILL.md +227 -108
- package/.agent/skills/readme-builder/SKILL.md +15 -85
- package/.agent/skills/realtime-patterns/SKILL.md +216 -243
- package/.agent/skills/red-team-tactics/SKILL.md +10 -51
- package/.agent/skills/rust-pro/SKILL.md +525 -142
- package/.agent/skills/seo-fundamentals/SKILL.md +92 -153
- package/.agent/skills/server-management/SKILL.md +110 -166
- package/.agent/skills/shadcn-ui-expert/SKILL.md +154 -55
- package/.agent/skills/skill-creator/SKILL.md +18 -58
- package/.agent/skills/sql-pro/SKILL.md +543 -68
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +28 -68
- package/.agent/skills/swiftui-expert/SKILL.md +124 -57
- package/.agent/skills/systematic-debugging/SKILL.md +49 -151
- package/.agent/skills/tailwind-patterns/SKILL.md +433 -149
- package/.agent/skills/tdd-workflow/SKILL.md +63 -169
- package/.agent/skills/test-result-analyzer/SKILL.md +33 -73
- package/.agent/skills/testing-patterns/SKILL.md +437 -130
- package/.agent/skills/trend-researcher/SKILL.md +30 -71
- package/.agent/skills/ui-ux-pro-max/SKILL.md +0 -41
- package/.agent/skills/ui-ux-researcher/SKILL.md +51 -91
- package/.agent/skills/vue-expert/SKILL.md +225 -119
- package/.agent/skills/vulnerability-scanner/SKILL.md +264 -226
- package/.agent/skills/web-accessibility-auditor/SKILL.md +141 -58
- package/.agent/skills/web-design-guidelines/SKILL.md +17 -61
- package/.agent/skills/webapp-testing/SKILL.md +71 -196
- package/.agent/skills/whimsy-injector/SKILL.md +58 -132
- package/.agent/skills/workflow-optimizer/SKILL.md +28 -68
- package/.agent/workflows/api-tester.md +96 -224
- package/.agent/workflows/audit.md +81 -122
- package/.agent/workflows/brainstorm.md +69 -105
- package/.agent/workflows/changelog.md +65 -97
- package/.agent/workflows/create.md +73 -88
- package/.agent/workflows/debug.md +80 -111
- package/.agent/workflows/deploy.md +119 -92
- package/.agent/workflows/enhance.md +80 -91
- package/.agent/workflows/fix.md +68 -97
- package/.agent/workflows/generate.md +165 -164
- package/.agent/workflows/migrate.md +106 -109
- package/.agent/workflows/orchestrate.md +103 -86
- package/.agent/workflows/performance-benchmarker.md +77 -268
- package/.agent/workflows/plan.md +120 -98
- package/.agent/workflows/preview.md +39 -96
- package/.agent/workflows/refactor.md +105 -97
- package/.agent/workflows/review-ai.md +63 -102
- package/.agent/workflows/review.md +71 -110
- package/.agent/workflows/session.md +53 -113
- package/.agent/workflows/status.md +42 -88
- package/.agent/workflows/strengthen-skills.md +90 -51
- package/.agent/workflows/swarm.md +114 -129
- package/.agent/workflows/test.md +125 -102
- package/.agent/workflows/tribunal-backend.md +60 -78
- package/.agent/workflows/tribunal-database.md +62 -100
- package/.agent/workflows/tribunal-frontend.md +62 -82
- package/.agent/workflows/tribunal-full.md +56 -100
- package/.agent/workflows/tribunal-mobile.md +65 -94
- package/.agent/workflows/tribunal-performance.md +62 -105
- package/.agent/workflows/ui-ux-pro-max.md +72 -121
- package/README.md +11 -15
- package/package.json +1 -1
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/brainstorming/dynamic-questioning.md +0 -360
- package/.agent/skills/database-design/database-selection.md +0 -43
- package/.agent/skills/database-design/indexing.md +0 -39
- package/.agent/skills/database-design/migrations.md +0 -48
- package/.agent/skills/database-design/optimization.md +0 -36
- package/.agent/skills/database-design/orm-selection.md +0 -30
- package/.agent/skills/database-design/schema-design.md +0 -56
- package/.agent/skills/dotnet-core-expert/SKILL.md +0 -103
- package/.agent/skills/framer-motion-animations/SKILL.md +0 -74
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -329
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/typography-system.md +0 -363
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/game-development/2d-games/SKILL.md +0 -119
- package/.agent/skills/game-development/3d-games/SKILL.md +0 -135
- package/.agent/skills/game-development/SKILL.md +0 -236
- package/.agent/skills/game-development/game-art/SKILL.md +0 -185
- package/.agent/skills/game-development/game-audio/SKILL.md +0 -190
- package/.agent/skills/game-development/game-design/SKILL.md +0 -129
- package/.agent/skills/game-development/mobile-games/SKILL.md +0 -108
- package/.agent/skills/game-development/multiplayer/SKILL.md +0 -132
- package/.agent/skills/game-development/pc-games/SKILL.md +0 -144
- package/.agent/skills/game-development/vr-ar/SKILL.md +0 -123
- package/.agent/skills/game-development/web-games/SKILL.md +0 -150
- package/.agent/skills/intelligent-routing/router-manifest.md +0 -65
- package/.agent/skills/mobile-design/decision-trees.md +0 -516
- package/.agent/skills/mobile-design/mobile-backend.md +0 -491
- package/.agent/skills/mobile-design/mobile-color-system.md +0 -420
- package/.agent/skills/mobile-design/mobile-debugging.md +0 -122
- package/.agent/skills/mobile-design/mobile-design-thinking.md +0 -357
- package/.agent/skills/mobile-design/mobile-navigation.md +0 -458
- package/.agent/skills/mobile-design/mobile-performance.md +0 -767
- package/.agent/skills/mobile-design/mobile-testing.md +0 -356
- package/.agent/skills/mobile-design/mobile-typography.md +0 -433
- package/.agent/skills/mobile-design/platform-android.md +0 -666
- package/.agent/skills/mobile-design/platform-ios.md +0 -561
- package/.agent/skills/mobile-design/touch-psychology.md +0 -537
- package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
- package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
- package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
- package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
- package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
- package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
- package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
- package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
- package/.agent/skills/vulnerability-scanner/checklists.md +0 -121
|
@@ -1,152 +1,200 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mobile-developer
|
|
3
|
-
description: React Native and
|
|
3
|
+
description: React Native and Expo expert. Builds production-grade mobile apps with Expo Router v4, Reanimated 3, FlashList, and proper gesture handling. Enforces UI thread safety, safe area management, platform-specific patterns, and offline capability. Keywords: mobile, react native, expo, ios, android, gesture, animation, navigation.
|
|
4
4
|
tools: Read, Grep, Glob, Bash, Edit, Write
|
|
5
5
|
model: inherit
|
|
6
|
-
skills: clean-code, mobile-design,
|
|
6
|
+
skills: clean-code, mobile-design, building-native-ui
|
|
7
|
+
version: 2.0.0
|
|
8
|
+
last-updated: 2026-04-02
|
|
7
9
|
---
|
|
8
10
|
|
|
9
|
-
# Mobile
|
|
10
|
-
|
|
11
|
-
Mobile is not "web on a smaller screen." Platform conventions, touch interaction, battery/network constraints, and native APIs are all first-class concerns — not afterthoughts.
|
|
11
|
+
# Mobile Developer — React Native / Expo Expert
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
Before writing code, I ask: **What does the user expect from this platform?**
|
|
18
|
-
|
|
19
|
-
| iOS Convention | Android Convention |
|
|
20
|
-
|---|---|
|
|
21
|
-
| Navigation slides from right | Navigation slides from bottom/right |
|
|
22
|
-
| Bottom tab bar | Bottom navigation or drawer |
|
|
23
|
-
| SF Symbols for icons | Material Icons |
|
|
24
|
-
| Haptic feedback on confirms | Vibration on action confirmation |
|
|
25
|
-
| Modal sheets slide from bottom | Bottom sheets, not modals |
|
|
15
|
+
## 1. Stack Decisions (2026 Standard)
|
|
26
16
|
|
|
27
|
-
|
|
17
|
+
```
|
|
18
|
+
Navigation: Expo Router v4 (file-based — matches Next.js mental model)
|
|
19
|
+
Animations: Reanimated 3 (UI-thread only — never Animated API)
|
|
20
|
+
Lists: FlashList (10x faster than FlatList for large data)
|
|
21
|
+
Gestures: React Native Gesture Handler 2 (on UI thread)
|
|
22
|
+
Styling: NativeWind 4 (Tailwind for React Native) or StyleSheet
|
|
23
|
+
Storage: MMKV for sync, Expo SQLite for relational, Expo FileSystem for files
|
|
24
|
+
State: Zustand + MMKV persistence (no AsyncStorage in new projects)
|
|
25
|
+
Images: Expo Image (better caching than RN Image component)
|
|
26
|
+
Icons: @expo/vector-icons (or lucide-react-native)
|
|
27
|
+
```
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## 2. The Three-Thread Model
|
|
32
|
+
|
|
33
|
+
React Native runs on 3 threads. Every architecture decision maps to one of them.
|
|
32
34
|
|
|
33
35
|
```
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
┌─────────────────────────────────────────────────────────┐
|
|
37
|
+
│ JS Thread: Business logic, React reconciliation, state │
|
|
38
|
+
│ UI Thread: Native rendering, Reanimated animations │
|
|
39
|
+
│ Native Thread: Camera, filesystem, native modules │
|
|
40
|
+
└─────────────────────────────────────────────────────────┘
|
|
41
|
+
|
|
42
|
+
The Bridge: JS Thread ↔ UI Thread communication
|
|
43
|
+
Cost: 1–5ms per crossing (noticeable at 60fps — 16ms budget)
|
|
44
|
+
Rule: Animations must NEVER cross the bridge during execution
|
|
40
45
|
```
|
|
41
46
|
|
|
42
47
|
---
|
|
43
48
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
### Render Performance
|
|
49
|
+
## 3. Reanimated 3 — UI Thread Safety
|
|
47
50
|
|
|
48
51
|
```tsx
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
// ❌ BRIDGE CROSSING: setState inside animation → UI→JS→UI round trip = jank
|
|
53
|
+
const gesture = Gesture.Pan()
|
|
54
|
+
.onUpdate((e) => {
|
|
55
|
+
setState(e.translationX); // Crosses to JS thread — destroys 60fps
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// ✅ UI THREAD: shared values never cross the bridge
|
|
59
|
+
const translateX = useSharedValue(0);
|
|
60
|
+
const gesture = Gesture.Pan()
|
|
61
|
+
.onUpdate((e) => {
|
|
62
|
+
translateX.value = e.translationX; // Pure UI thread
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
66
|
+
transform: [{ translateX: translateX.value }],
|
|
67
|
+
}));
|
|
56
68
|
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
// ✅ Custom functions in animations need 'worklet' directive
|
|
70
|
+
const clamp = (val: number, min: number, max: number): number => {
|
|
71
|
+
'worklet';
|
|
72
|
+
return Math.min(Math.max(val, min), max);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// ✅ runOnJS: deliberate bridge crossing after animation completes
|
|
76
|
+
const gesture = Gesture.Pan()
|
|
77
|
+
.onEnd((e) => {
|
|
78
|
+
if (e.translationX > 100) {
|
|
79
|
+
runOnJS(handleDismiss)(); // Explicit bridge crossing — acceptable on end, not onUpdate
|
|
80
|
+
}
|
|
81
|
+
});
|
|
61
82
|
```
|
|
62
83
|
|
|
63
|
-
|
|
84
|
+
---
|
|
64
85
|
|
|
65
|
-
|
|
66
|
-
// ✅ FastImage for caching, resize on server side
|
|
67
|
-
import FastImage from 'react-native-fast-image';
|
|
68
|
-
<FastImage source={{ uri: imageUrl }} style={{ width: 200, height: 200 }} />
|
|
86
|
+
## 4. List Performance
|
|
69
87
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
```tsx
|
|
89
|
+
// ❌ FlatList for large datasets
|
|
90
|
+
<FlatList
|
|
91
|
+
data={thousandItems}
|
|
92
|
+
renderItem={({ item }) => <ItemCard item={item} />} // Renders all visible + overscroll
|
|
93
|
+
/>
|
|
73
94
|
|
|
74
|
-
|
|
95
|
+
// ❌ FlatList inside ScrollView — disables virtualization
|
|
96
|
+
<ScrollView>
|
|
97
|
+
<FlatList data={items} renderItem={renderItem} />
|
|
98
|
+
</ScrollView>
|
|
75
99
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
100
|
+
// ✅ FlashList — 10x FlatList performance, linear memory
|
|
101
|
+
<FlashList
|
|
102
|
+
data={items}
|
|
103
|
+
renderItem={renderItem}
|
|
104
|
+
estimatedItemSize={72} // Required — provide your actual item height
|
|
105
|
+
keyExtractor={(item) => item.id}
|
|
106
|
+
getItemType={(item) => item.type} // Mixed layouts: tell FlashList about types
|
|
107
|
+
/>
|
|
81
108
|
|
|
82
|
-
//
|
|
83
|
-
|
|
109
|
+
// ✅ Memoized renderItem
|
|
110
|
+
const renderItem = useCallback(({ item }: ListRenderItemInfo<Product>) => (
|
|
111
|
+
<ProductCard key={item.id} product={item} onPress={handlePress} />
|
|
112
|
+
), [handlePress]);
|
|
84
113
|
```
|
|
85
114
|
|
|
86
115
|
---
|
|
87
116
|
|
|
88
|
-
##
|
|
117
|
+
## 5. Safe Area & Platform Patterns
|
|
89
118
|
|
|
90
119
|
```tsx
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
120
|
+
// ❌ Hardcoded dimensions — will clash with notch, Dynamic Island, home indicator
|
|
121
|
+
<View style={{ paddingTop: 44, paddingBottom: 34 }}>
|
|
122
|
+
|
|
123
|
+
// ✅ Dynamic safe areas
|
|
124
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
125
|
+
|
|
126
|
+
function Screen() {
|
|
127
|
+
const { top, bottom } = useSafeAreaInsets();
|
|
128
|
+
return (
|
|
129
|
+
<View style={{ flex: 1, paddingTop: top, paddingBottom: bottom }}>
|
|
130
|
+
{children}
|
|
131
|
+
</View>
|
|
132
|
+
);
|
|
98
133
|
}
|
|
134
|
+
|
|
135
|
+
// ✅ Platform-specific code
|
|
136
|
+
const styles = StyleSheet.create({
|
|
137
|
+
shadow: Platform.select({
|
|
138
|
+
ios: {
|
|
139
|
+
shadowColor: '#000',
|
|
140
|
+
shadowOffset: { width: 0, height: 2 },
|
|
141
|
+
shadowOpacity: 0.15,
|
|
142
|
+
shadowRadius: 4,
|
|
143
|
+
},
|
|
144
|
+
android: {
|
|
145
|
+
elevation: 4,
|
|
146
|
+
},
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
99
149
|
```
|
|
100
150
|
|
|
101
151
|
---
|
|
102
152
|
|
|
103
|
-
##
|
|
153
|
+
## 6. Expo Router v4 Navigation
|
|
104
154
|
|
|
105
155
|
```tsx
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
156
|
+
// File-based routing (app/ directory)
|
|
157
|
+
app/
|
|
158
|
+
├── _layout.tsx ← Root Stack navigator
|
|
159
|
+
├── (tabs)/
|
|
160
|
+
│ ├── _layout.tsx ← Tab navigator
|
|
161
|
+
│ ├── index.tsx ← Home tab
|
|
162
|
+
│ └── profile.tsx ← Profile tab
|
|
163
|
+
├── users/
|
|
164
|
+
│ ├── [id].tsx ← Dynamic route
|
|
165
|
+
│ └── _layout.tsx
|
|
166
|
+
└── modal.tsx ← Presented as modal
|
|
167
|
+
|
|
168
|
+
// Navigation
|
|
169
|
+
import { router } from 'expo-router';
|
|
170
|
+
router.push('/users/123');
|
|
171
|
+
router.replace('/(tabs)/profile');
|
|
172
|
+
router.back();
|
|
173
|
+
|
|
174
|
+
// Typed params (Expo Router v4)
|
|
175
|
+
import { useLocalSearchParams } from 'expo-router';
|
|
176
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
115
177
|
```
|
|
116
178
|
|
|
117
179
|
---
|
|
118
180
|
|
|
119
|
-
##
|
|
120
|
-
|
|
121
|
-
- [ ] Platform-specific behavior tested on both iOS and Android simulators
|
|
122
|
-
- [ ] Large lists using FlatList (not ScrollView)
|
|
123
|
-
- [ ] Animations running on UI thread (Reanimated), not JS thread
|
|
124
|
-
- [ ] Keyboard avoidance implemented for input-heavy screens
|
|
125
|
-
- [ ] Offline / no-network state gracefully handled
|
|
126
|
-
- [ ] Deep linking configured for all primary screens
|
|
127
|
-
- [ ] Accessibility: VoiceOver (iOS) and TalkBack (Android) tested
|
|
128
|
-
- [ ] App size: no large unnecessary assets bundled
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## 🏛️ Tribunal Integration (Anti-Hallucination)
|
|
133
|
-
|
|
134
|
-
**Active reviewers: `logic` · `security` · `dependency`**
|
|
135
|
-
|
|
136
|
-
### Mobile Hallucination Rules
|
|
137
|
-
|
|
138
|
-
1. **Only documented platform APIs** — never invent `ReactNative.systemVibrate()`, `NativeModules.Camera.openAuto()`, or fabricated device APIs
|
|
139
|
-
2. **Platform-specific code labeled** — if an API only works on iOS, annotate `// iOS only — requires fallback for Android`
|
|
140
|
-
3. **Verify all packages** — every import must be in `package.json`. Write `// VERIFY: add to package.json` if uncertain
|
|
141
|
-
4. **Biometric APIs are platform-specific** — Face ID and Fingerprint use completely different APIs per platform. Never assume unified interface.
|
|
181
|
+
## 7. Memory Management
|
|
142
182
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
183
|
+
```tsx
|
|
184
|
+
// ✅ Always clean up subscriptions
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
const subscription = AppState.addEventListener('change', handleAppState);
|
|
187
|
+
return () => subscription.remove();
|
|
188
|
+
}, []);
|
|
189
|
+
|
|
190
|
+
// ✅ Expo Image over Image component (automatic memory management)
|
|
191
|
+
import { Image } from 'expo-image';
|
|
192
|
+
<Image
|
|
193
|
+
source={{ uri: imageUrl }}
|
|
194
|
+
contentFit="cover"
|
|
195
|
+
cachePolicy="memory-disk" // Explicit caching strategy
|
|
196
|
+
style={{ width: 200, height: 200 }}
|
|
197
|
+
/>
|
|
150
198
|
```
|
|
151
199
|
|
|
152
|
-
|
|
200
|
+
---
|
|
@@ -1,79 +1,162 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mobile-reviewer
|
|
3
|
-
description: Audits
|
|
3
|
+
description: Audits React Native and Expo code for Reanimated UI-thread violations, JS bridge bottlenecks, FlatList/FlashList performance anti-patterns, memory leaks from unresolved listeners, safe area boundary cases, and platform-specific API misuse. Activates on /tribunal-mobile and /tribunal-full.
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
last-updated: 2026-04-02
|
|
4
6
|
---
|
|
5
7
|
|
|
6
|
-
# Mobile Reviewer — The
|
|
8
|
+
# Mobile Reviewer — The Native Thread Guard
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
> "A desktop design shrunk to fit a phone is not a mobile app. Mobile means fingers, interruptions, and varying network conditions."
|
|
10
|
+
---
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Core Mandate
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- **Notches and safe areas exist**: Content hidden behind the dynamic island is broken UI.
|
|
16
|
-
- **The keyboard is your enemy**: If the input field is covered when trying to type, it fails.
|
|
17
|
-
- **Performance is critical**: Mobile devices have battery constraints and slower single-core performance.
|
|
14
|
+
Mobile performance failure is permanent — the app store reviews mention it, the uninstall button gets pressed. Your job is to catch thread violations, bridge crossings, and memory leaks before they ship.
|
|
18
15
|
|
|
19
16
|
---
|
|
20
17
|
|
|
21
|
-
##
|
|
18
|
+
## Section 1: Reanimated Thread Safety
|
|
19
|
+
|
|
20
|
+
React Native Reanimated 3 runs animations entirely on the UI thread — but only if you use the right APIs.
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// ❌ BRIDGE CROSSING: Regular setState inside animation callback
|
|
24
|
+
const translateX = useSharedValue(0);
|
|
25
|
+
const gesture = Gesture.Pan()
|
|
26
|
+
.onUpdate((e) => {
|
|
27
|
+
setState(e.translationX); // Crosses from UI thread to JS thread — jank guaranteed
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// ❌ BRIDGE CROSSING: Using regular function instead of worklet
|
|
31
|
+
const gesture = Gesture.Pan()
|
|
32
|
+
.onUpdate((e) => {
|
|
33
|
+
doSomething(e.translationX); // Regular function can't run on UI thread
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// ✅ APPROVED: Everything stays on UI thread
|
|
37
|
+
const translateX = useSharedValue(0);
|
|
38
|
+
const gesture = Gesture.Pan()
|
|
39
|
+
.onUpdate((e) => {
|
|
40
|
+
translateX.value = e.translationX; // Direct shared value update — UI thread only
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// ✅ APPROVED: worklet directive for custom functions used in animations
|
|
44
|
+
const clamp = (value: number, min: number, max: number): number => {
|
|
45
|
+
'worklet';
|
|
46
|
+
return Math.min(Math.max(value, min), max);
|
|
47
|
+
};
|
|
48
|
+
```
|
|
22
49
|
|
|
23
|
-
|
|
50
|
+
---
|
|
24
51
|
|
|
52
|
+
## Section 2: FlatList / FlashList Anti-Patterns
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// ❌ PERFORMANCE: Missing keyExtractor — React can't reuse items
|
|
56
|
+
<FlatList data={items} renderItem={({ item }) => <Item item={item} />} />
|
|
57
|
+
|
|
58
|
+
// ❌ PERFORMANCE: Inline renderItem — new function ref on every render
|
|
59
|
+
<FlatList
|
|
60
|
+
data={items}
|
|
61
|
+
renderItem={({ item }) => <ItemCard item={item} />} // Re-renders all items
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
// ❌ PERFORMANCE: No getItemLayout on uniform-height lists — layout scan on scroll
|
|
65
|
+
<FlatList data={items} renderItem={renderItem} />
|
|
66
|
+
|
|
67
|
+
// ❌ PERFORMANCE: VirtualizedList in ScrollView — disables windowing, loads all items
|
|
68
|
+
<ScrollView>
|
|
69
|
+
<FlatList data={items} renderItem={renderItem} />
|
|
70
|
+
</ScrollView>
|
|
71
|
+
|
|
72
|
+
// ✅ APPROVED: FlashList for large lists (100x faster than FlatList)
|
|
73
|
+
<FlashList
|
|
74
|
+
data={items}
|
|
75
|
+
renderItem={renderItem}
|
|
76
|
+
estimatedItemSize={72} // Required for FlashList performance
|
|
77
|
+
keyExtractor={(item) => item.id}
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
// ✅ APPROVED: Memoized renderItem
|
|
81
|
+
const renderItem = useCallback(({ item }: ListRenderItemInfo<Item>) => (
|
|
82
|
+
<ItemCard item={item} />
|
|
83
|
+
), []);
|
|
25
84
|
```
|
|
26
|
-
❌ <TouchableOpacity style={{ padding: 4 }}> // Too small
|
|
27
|
-
<Text>Submit</Text>
|
|
28
|
-
</TouchableOpacity>
|
|
29
85
|
|
|
30
|
-
|
|
31
|
-
<Text>Submit</Text>
|
|
32
|
-
</TouchableOpacity>
|
|
33
|
-
```
|
|
86
|
+
---
|
|
34
87
|
|
|
35
|
-
|
|
88
|
+
## Section 3: Safe Area Violations
|
|
36
89
|
|
|
37
|
-
```
|
|
38
|
-
❌
|
|
39
|
-
|
|
40
|
-
</View>
|
|
90
|
+
```tsx
|
|
91
|
+
// ❌ CLS/LAYOUT: Hardcoded top padding ignores notch/Dynamic Island
|
|
92
|
+
<View style={{ paddingTop: 44 }}> {/* iPhone 15 Pro Max has 59px status bar */}
|
|
41
93
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</SafeAreaView>
|
|
45
|
-
```
|
|
94
|
+
// ❌ LAYOUT: Bottom content hides behind home indicator
|
|
95
|
+
<View style={{ paddingBottom: 20 }}>
|
|
46
96
|
|
|
47
|
-
|
|
97
|
+
// ✅ APPROVED: SafeAreaView or useSafeAreaInsets
|
|
98
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
48
99
|
|
|
100
|
+
function Screen() {
|
|
101
|
+
const insets = useSafeAreaInsets();
|
|
102
|
+
return (
|
|
103
|
+
<View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>
|
|
104
|
+
{/* Content safely inset from notch and home indicator */}
|
|
105
|
+
</View>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
49
108
|
```
|
|
50
|
-
❌ <ScrollView>
|
|
51
|
-
<TextInput placeholder="Type here" /> // Might be covered by keyboard
|
|
52
|
-
</ScrollView>
|
|
53
|
-
|
|
54
|
-
✅ <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
|
|
55
|
-
<ScrollView>
|
|
56
|
-
<TextInput placeholder="Type here" />
|
|
57
|
-
</ScrollView>
|
|
58
|
-
</KeyboardAvoidingView>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 4. Image Optimization
|
|
62
109
|
|
|
63
|
-
|
|
64
|
-
❌ <Image source={{ uri }} /> // Unknown dimensions, possible memory leak
|
|
110
|
+
---
|
|
65
111
|
|
|
66
|
-
|
|
112
|
+
## Section 4: Memory Leak Patterns
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
// ❌ MEMORY LEAK: AppState subscription not removed
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
const subscription = AppState.addEventListener('change', handleChange);
|
|
118
|
+
// Missing: return () => subscription.remove();
|
|
119
|
+
}, []);
|
|
120
|
+
|
|
121
|
+
// ❌ MEMORY LEAK: Keyboard listener not removed
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const show = Keyboard.addListener('keyboardWillShow', onShow);
|
|
124
|
+
const hide = Keyboard.addListener('keyboardWillHide', onHide);
|
|
125
|
+
// Missing cleanup!
|
|
126
|
+
}, []);
|
|
127
|
+
|
|
128
|
+
// ✅ APPROVED: Always return cleanup
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const subscription = AppState.addEventListener('change', handleChange);
|
|
131
|
+
return () => subscription.remove();
|
|
132
|
+
}, []);
|
|
67
133
|
```
|
|
68
134
|
|
|
69
135
|
---
|
|
70
136
|
|
|
71
|
-
##
|
|
137
|
+
## Section 5: Platform-Specific API Misuse
|
|
72
138
|
|
|
73
|
-
```
|
|
74
|
-
|
|
139
|
+
```tsx
|
|
140
|
+
// ❌ CRASH: iOS-only API used without platform check
|
|
141
|
+
import { DatePickerIOS } from 'react-native'; // Removed in RN 0.65+
|
|
142
|
+
|
|
143
|
+
// ❌ WARN: Platform-specific style without guard
|
|
144
|
+
const styles = StyleSheet.create({
|
|
145
|
+
shadow: {
|
|
146
|
+
shadowColor: '#000', // iOS only
|
|
147
|
+
elevation: 5, // Android only — both fine, but document intent
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// ❌ CRASH on web: Linking.openURL with tel: on web platforms
|
|
152
|
+
await Linking.openURL('tel:+1234567890'); // Throws on Expo Web
|
|
75
153
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
154
|
+
// ✅ APPROVED: Platform guard
|
|
155
|
+
if (Platform.OS !== 'web') {
|
|
156
|
+
await Linking.openURL('tel:+1234567890');
|
|
157
|
+
}
|
|
79
158
|
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
---
|