adynato-mobile

Mobile app development conventions for Adynato projects using React Native and Expo. Covers navigation patterns, native APIs, performance optimization, and platform-specific considerations. Use when building or modifying mobile applications.

16 stars

Best use case

adynato-mobile is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Mobile app development conventions for Adynato projects using React Native and Expo. Covers navigation patterns, native APIs, performance optimization, and platform-specific considerations. Use when building or modifying mobile applications.

Teams using adynato-mobile should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/adynato-mobile/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/adynato-mobile/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/adynato-mobile/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How adynato-mobile Compares

Feature / Agentadynato-mobileStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Mobile app development conventions for Adynato projects using React Native and Expo. Covers navigation patterns, native APIs, performance optimization, and platform-specific considerations. Use when building or modifying mobile applications.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Mobile Development Skill

Use this skill for all Adynato mobile projects built with React Native and Expo.

## Stack

- **Framework**: Expo (managed workflow preferred)
- **Navigation**: Expo Router (file-based routing)
- **Styling**: NativeWind (Tailwind for React Native)
- **State**: Zustand or React Context
- **Data Fetching**: TanStack Query

## API-Driven UI (Critical)

**Maximize API-driven content to enable instant updates without App Store review.**

App Store review can take 1-7 days. Any UI that can be server-controlled should be, so you can update instantly.

### What Should Be API-Driven

| Component | Why |
|-----------|-----|
| **Feature flags** | Enable/disable features without release |
| **Copy/text** | Fix typos, update messaging instantly |
| **Images/assets** | Swap promotional banners, icons |
| **Lists/feeds** | Content order, filtering, what's shown |
| **Navigation items** | Add/remove/reorder tabs and menus |
| **Form fields** | Add/remove fields, change validation |
| **Onboarding flows** | A/B test, iterate without releases |
| **Pricing/plans** | Update pricing, add tiers |
| **App config** | Timeouts, thresholds, limits |

### What Must Be Native

- Core navigation structure (Expo Router screens)
- Native module integrations
- Performance-critical animations
- Offline-first functionality

### Implementation Pattern

```tsx
// API returns UI configuration
interface HomeConfig {
  sections: Section[]
  featuredBanner?: Banner
  quickActions: QuickAction[]
}

function HomeScreen() {
  const { data: config } = useQuery({
    queryKey: ['home', 'config'],
    queryFn: () => api.get<HomeConfig>('/api/home/config'),
    staleTime: 1000 * 60 * 5, // Cache 5 min
  })

  return (
    <ScrollView>
      {config?.featuredBanner && (
        <Banner data={config.featuredBanner} />
      )}
      {config?.sections.map(section => (
        <DynamicSection key={section.id} config={section} />
      ))}
    </ScrollView>
  )
}
```

### Feature Flags

```tsx
// lib/features.ts
import { useQuery } from '@tanstack/react-query'

interface FeatureFlags {
  newCheckout: boolean
  darkMode: boolean
  betaFeatures: boolean
}

export function useFeatureFlags() {
  return useQuery({
    queryKey: ['features'],
    queryFn: () => api.get<FeatureFlags>('/api/features'),
    staleTime: 1000 * 60 * 15, // 15 min
  })
}

// Usage
function CheckoutButton() {
  const { data: flags } = useFeatureFlags()

  if (flags?.newCheckout) {
    return <NewCheckoutFlow />
  }
  return <LegacyCheckout />
}
```

### Remote Config for Copy

```tsx
// Fetch all app copy from API
const { data: copy } = useQuery({
  queryKey: ['copy', locale],
  queryFn: () => api.get(`/api/copy/${locale}`),
})

// Use with fallback
<Text>{copy?.welcomeMessage ?? 'Welcome!'}</Text>
```

### Server-Driven Lists

```tsx
// API controls what appears and in what order
interface FeedConfig {
  items: FeedItem[]
  layout: 'grid' | 'list'
  columns?: number
}

function Feed() {
  const { data } = useQuery<FeedConfig>({
    queryKey: ['feed'],
    queryFn: () => api.get('/api/feed'),
  })

  if (data?.layout === 'grid') {
    return <GridView items={data.items} columns={data.columns} />
  }
  return <ListView items={data.items} />
}
```

### Cache Strategy

Balance freshness with offline support:

```tsx
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5,    // Fresh for 5 min
      gcTime: 1000 * 60 * 60 * 24, // Keep in cache 24h
    },
  },
})
```

## Project Structure

```
app/
├── (tabs)/
│   ├── _layout.tsx
│   ├── index.tsx
│   └── profile.tsx
├── (auth)/
│   ├── _layout.tsx
│   ├── login.tsx
│   └── register.tsx
├── _layout.tsx
└── +not-found.tsx
components/
├── ui/
│   ├── Button.tsx
│   └── Input.tsx
└── [feature]/
hooks/
lib/
constants/
assets/
├── images/
└── fonts/
```

## Navigation

### Expo Router Patterns

```tsx
// app/_layout.tsx - Root layout
import { Stack } from 'expo-router'

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="(auth)" options={{ headerShown: false }} />
    </Stack>
  )
}
```

```tsx
// app/(tabs)/_layout.tsx - Tab navigation
import { Tabs } from 'expo-router'
import { Home, User } from 'lucide-react-native'

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen
        name="index"
        options={{
          title: 'Home',
          tabBarIcon: ({ color }) => <Home color={color} />,
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: 'Profile',
          tabBarIcon: ({ color }) => <User color={color} />,
        }}
      />
    </Tabs>
  )
}
```

### Navigation Actions

```tsx
import { router } from 'expo-router'

// Navigate
router.push('/profile')
router.replace('/home')
router.back()

// With params
router.push({
  pathname: '/user/[id]',
  params: { id: '123' }
})
```

## Components

### Platform-Specific Styles

```tsx
import { Platform, StyleSheet } from 'react-native'

const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 50 : 30,
    ...Platform.select({
      ios: { shadowColor: '#000' },
      android: { elevation: 4 },
    }),
  },
})
```

### Safe Area Handling

```tsx
import { SafeAreaView } from 'react-native-safe-area-context'

export function Screen({ children }) {
  return (
    <SafeAreaView className="flex-1 bg-white dark:bg-gray-900">
      {children}
    </SafeAreaView>
  )
}
```

### Pressable Over TouchableOpacity

```tsx
import { Pressable, Text } from 'react-native'

<Pressable
  onPress={handlePress}
  className="active:opacity-70 bg-blue-500 px-4 py-2 rounded-lg"
>
  <Text className="text-white font-semibold">Press Me</Text>
</Pressable>
```

## Images in Mobile

### Using Expo Image

Prefer `expo-image` over React Native's Image:

```tsx
import { Image } from 'expo-image'

<Image
  source={{ uri: 'https://example.com/image.webp' }}
  style={{ width: 200, height: 200 }}
  contentFit="cover"
  placeholder={blurhash}
  transition={200}
/>
```

### Local Images

```tsx
import { Image } from 'expo-image'

<Image
  source={require('@/assets/images/logo.png')}
  style={{ width: 100, height: 100 }}
/>
```

## Native APIs

### Permissions Pattern

```tsx
import * as Location from 'expo-location'

async function requestLocation() {
  const { status } = await Location.requestForegroundPermissionsAsync()

  if (status !== 'granted') {
    // Handle denial gracefully
    return null
  }

  return await Location.getCurrentPositionAsync({})
}
```

### Secure Storage

```tsx
import * as SecureStore from 'expo-secure-store'

// Store sensitive data
await SecureStore.setItemAsync('token', authToken)

// Retrieve
const token = await SecureStore.getItemAsync('token')

// Delete
await SecureStore.deleteItemAsync('token')
```

## Performance

### List Optimization

```tsx
import { FlashList } from '@shopify/flash-list'

<FlashList
  data={items}
  renderItem={({ item }) => <ItemCard item={item} />}
  estimatedItemSize={100}
  keyExtractor={(item) => item.id}
/>
```

### Memoization

```tsx
import { memo, useCallback, useMemo } from 'react'

const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
  const processed = useMemo(() => processData(data), [data])
  const handlePress = useCallback(() => { ... }, [])

  return <View>...</View>
})
```

## Testing

### Component Testing

```tsx
import { render, fireEvent } from '@testing-library/react-native'
import { Button } from '@/components/ui/Button'

test('Button calls onPress', () => {
  const onPress = jest.fn()
  const { getByText } = render(<Button onPress={onPress}>Click</Button>)

  fireEvent.press(getByText('Click'))
  expect(onPress).toHaveBeenCalled()
})
```

## Build & Deploy

### EAS Build

```bash
# Development build
eas build --profile development --platform ios

# Production
eas build --profile production --platform all
```

### Environment Variables

```tsx
// Use expo-constants for env vars
import Constants from 'expo-constants'

const apiUrl = Constants.expoConfig?.extra?.apiUrl
```

## Checklist

Before releasing:

- [ ] **UI is API-driven where possible** (copy, config, feature flags)
- [ ] Tested on both iOS and Android
- [ ] Safe area handling on all screens
- [ ] Keyboard avoiding views where needed
- [ ] Loading and error states for all async operations
- [ ] Offline handling considered
- [ ] Deep linking configured
- [ ] App icons and splash screen set
- [ ] Performance profiled (no jank)

Related Skills

agent-mobile-developer

16
from diegosouzapw/awesome-omni-skill

Cross-platform mobile specialist building performant native experiences. Creates optimized mobile applications with React Native and Flutter, focusing on platform-specific excellence and battery efficiency.

agent-mobile-app-developer

16
from diegosouzapw/awesome-omni-skill

Expert mobile app developer specializing in native and cross-platform development for iOS and Android. Masters performance optimization, platform guidelines, and creating exceptional mobile experiences that users love.

adynato-web

16
from diegosouzapw/awesome-omni-skill

Web development conventions for Adynato projects. Covers image optimization with img4web, asset management, component patterns, styling, and performance best practices. Use when building or modifying web applications, adding images/assets, or creating UI components.

accessibility-mobile

16
from diegosouzapw/awesome-omni-skill

React Native accessibility patterns for iOS and Android. Use when implementing a11y features.

mobile-first-design-rules

16
from diegosouzapw/awesome-omni-skill

Focuses on rules and best practices for mobile-first design and responsive typography using tailwind.

adynato-aimake

16
from diegosouzapw/awesome-omni-skill

Integrate with aimake's AI-powered delivery pipeline via MCP. Covers connecting to aimake, using code/docs/kanban tools, understanding the card-based system, and leveraging AI capabilities. Use when building integrations with aimake or using its MCP tools.

adynato-github

16
from diegosouzapw/awesome-omni-skill

GitHub workflow conventions for Adynato projects. Covers creating PRs with gh CLI, writing thorough descriptions, and using stacked PRs for large deliverables. Use when creating pull requests, managing branches, or breaking down large features.

adynato-seo

16
from diegosouzapw/awesome-omni-skill

Handles SEO requirements for all web content including blogs, landing pages, and documentation. Covers LD+JSON schema.org structured data, internal backlinks strategy, further reading sections, meta tags, and Open Graph. Use when creating or editing any public-facing web content, blog posts, or pages that need search visibility.

Mobile Ci Cd

16
from diegosouzapw/awesome-omni-skill

Mobile CI/CD automates building, testing, and deploying mobile applications. This guide covers GitHub Actions, Fastlane automation, code signing, and App Store submission automation for streamlining m

adynato-web-api

16
from diegosouzapw/awesome-omni-skill

Web API development conventions for Adynato projects. Covers API routes, middleware, authentication, error handling, validation, and response formats for Next.js and Node.js backends. Use when building or modifying API endpoints, server actions, or backend logic.

adynato-mobile-api

16
from diegosouzapw/awesome-omni-skill

API integration patterns for Adynato mobile apps. Covers data fetching with TanStack Query, authentication flows, offline support, error handling, and optimistic updates in React Native/Expo apps. Use when integrating APIs into mobile applications.

bgo

10
from diegosouzapw/awesome-omni-skill

Automates the complete Blender build-go workflow, from building and packaging your extension/add-on to removing old versions, installing, enabling, and launching Blender for quick testing and iteration.

Coding & Development