AgentStack
SKILL verified MIT Self-run

App L100

skill-leo-atienza-atlas-claude-app-l100 · by Leo-Atienza

A Claude skill from Leo-Atienza/atlas-claude.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-leo-atienza-atlas-claude-app-l100

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of App L100? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Universal App Conductor — Building Premium Apps Across All Platforms

When to Use This Skill

Auto-activate when: building any native app — mobile (React Native/Expo), desktop (Tauri), universal (multi-platform), iOS/Swift, or any app requiring device hardware, offline-first, or on-device AI. This is the CONDUCTOR skill for all native/cross-platform development.

This skill does NOT replace specialist skills. It orchestrates them.

The Skill Map

| Task | Load Skill | ID | |------|-----------|-----| | React Native performance & patterns | react-native | SK-016 | | Expo deployment & builds | expo-deployment | (archived, auto-activate) | | Expo CI/CD workflows | expo-cicd-workflows | (archived, auto-activate) | | Tauri desktop apps | tauri-desktop | SK-088 | | Camera, scanning, biometrics, sensors | device-hardware-bridge | SK-089 | | Offline-first, CRDT sync | local-first-architecture | SK-090 | | On-device AI, ML inference, RAG | edge-intelligence | SK-091 | | Multi-platform monorepo | crossplatform-monorepo | SK-092 | | Native animations & motion | motion-native | SK-097 | | 2D/3D visual rendering (Skia, Rive, R3F) | visual-native | SK-098 | | Screen transitions & smooth scroll | transition-native | SK-099 | | Sensory design (haptics + sound + motion tokens) | sensory-native | SK-100 | | Swift concurrency review | swift-concurrency-pro | SK-035 | | SwiftUI code review | swiftui-pro | SK-037 | | Swift testing | swift-testing-pro | SK-036 | | Data fetching & caching | tanstack-ecosystem | SK-055 | | Unit/component testing | vitest-testing | SK-056 | | Advanced JS/TS patterns | advanced-javascript | SK-045 | | Design aesthetics | frontend-design | SK-005 | | E2E testing (mobile + desktop) | e2e-testing | SK-027 |


Platform Decision Matrix

| Scenario | Recommendation | |---|---| | New mobile app, team knows React | Expo SDK 54 (Managed Workflow) | | Need custom native SDK not in Expo | Expo (Bare Workflow) with config plugins | | Deep native customization, existing native team | React Native bare | | iOS-only, premium native feel critical | Swift/SwiftUI native | | Universal app (web + iOS + Android) | Expo + Expo Router + NativeWind | | Shared codebase with Next.js web app | Turborepo monorepo + Expo + Next.js (SK-092) | | Desktop app (Windows/macOS/Linux) | Tauri 2.0 (SK-088) | | Desktop + mobile from one codebase | Tauri 2.0 with mobile targets (SK-088) | | Multi-platform (mobile + desktop + web) | Turborepo monorepo (SK-092) + Expo + Tauri + Next.js | | Offline-first app with sync | Local-First Architecture (SK-090) + framework of choice | | App with on-device AI/ML | Edge Intelligence (SK-091) + framework of choice | | Camera/scanning/sensor-heavy app | Device Hardware Bridge (SK-089) + framework of choice |


The Full Stack (2026)

Mobile:        Expo SDK 54 / Expo Router v4 / React Native 0.82+ (New Architecture mandatory)
Desktop:       Tauri 2.0 (Rust backend + system WebView, 96% smaller than Electron)
Animation:     Reanimated 4 (mobile) / Motion + GSAP (desktop/web)
Local-First:   PowerSync / TinyBase v5 / Legend State v3
On-Device AI:  llama.rn / MediaPipe / sqlite-vec (on-device RAG pipeline)
Hardware:      Vision Camera v5 / expo-camera / Tauri plugins
State:         Zustand v5 + TanStack Query (server) + Jotai v2 (atomic)
Monorepo:      Turborepo + shared packages
Build:         React Compiler (default), precompiled iOS XCFrameworks

Expo SDK 54 Highlights

  • Precompiled React Native for iOS — XCFrameworks reduce clean build ~120s → ~10s
  • React Compiler enabled by default — automatic memoization
  • sqlite-vec — on-device vector search for RAG pipelines
  • TextDecoderStream — streaming AI responses (local or remote)
  • expo-app-integrity — DeviceCheck (iOS) + Play Integrity (Android)
  • Liquid Glass (iOS 26)expo-glass-effect, native tabs with glass sheen
  • Edge-to-edge Android 16 — always enabled, cannot be disabled

Tauri Thread Model (Desktop)

┌─────────────────────────┐
│   Frontend (WebView)     │  React/Svelte/Vue — your existing web code
│   (system WebView2/WKW)  │  Animations, UI state, user interaction
└────────┬────────────────┘
         │ IPC: Commands + Events + Channels
┌────────▼────────────────┐
│   Rust Core              │  Business logic, file system, crypto, plugins
│   (compiled, type-safe)  │  Heavy computation, system access
└────────┬────────────────┘
         │
┌────────▼────────────────┐
│   System APIs            │  OS notifications, tray, clipboard, updater
└─────────────────────────┘

Performance:

); }


### Storage (MMKV — 30x faster than AsyncStorage)

```tsx
// lib/storage.ts
import { MMKV } from 'react-native-mmkv';

export const storage = new MMKV();

// Synchronous — no await needed
storage.set('user.token', token);
const token = storage.getString('user.token');
storage.delete('user.token');

TanStack Query + MMKV Persistence (Offline-First)

// lib/query.ts
import { QueryClient } from '@tanstack/react-query';
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
import { storage } from './storage';

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60 * 1000,
      gcTime: 24 * 60 * 60 * 1000,
      retry: 2,
    },
  },
});

export const persister = createSyncStoragePersister({
  storage: {
    getItem: (key) => storage.getString(key) ?? null,
    setItem: (key, value) => storage.set(key, value),
    removeItem: (key) => storage.delete(key),
  },
});

Haptic Feedback — Every Interaction Gets a Tap

// hooks/useHaptic.ts
import * as Haptics from 'expo-haptics';

export const useHaptic = () => ({
  tap: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium),
  light: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light),
  heavy: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy),
  select: () => Haptics.selectionAsync(),
  success: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success),
  error: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error),
  warning: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning),
});

When to use which:

| Interaction | Haptic | Notes | |---|---|---| | Button tap | tap() (Medium) | Every interactive button | | Toggle / switch | light() | On state change, not on press | | Picker scroll step | select() | Each item tick | | Form submit success | success() | One-time confirmation | | Delete confirm | warning() | Before the destructive action | | Auth/validation error | error() | | | Drag start | tap() | | | Drag drop / snap | heavy() | Landing feeling | | Long press (context menu) | heavy() | |


Animation Patterns

Button with Press Feedback (Gesture Handler, NOT Pressable)

import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
import * as Haptics from 'expo-haptics';

function AnimatedButton({ onPress, children }: Props) {
  const scale = useSharedValue(1);

  const tap = Gesture.Tap()
    .onBegin(() => {
      'worklet';
      scale.value = withSpring(0.95, { damping: 20, stiffness: 400 });
    })
    .onFinalize((_e, success) => {
      'worklet';
      scale.value = withSpring(1, { damping: 15, stiffness: 300 });
      if (success) {
        runOnJS(Haptics.impactAsync)(Haptics.ImpactFeedbackStyle.Medium);
        runOnJS(onPress)();
      }
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  return (
    
      {children}
    
  );
}

Why GestureDetector over Pressable: Pressable.onPressIn routes through JS thread. Gesture.Tap().onBegin runs as a worklet on UI thread — zero-latency animation start.

Screen Entrance (Moti — Declarative)

import { MotiView } from 'moti';

function ScreenContent() {
  return (
    
      {/* Screen content */}
    
  );
}

Staggered List Entrance (Moti)

import { MotiView } from 'moti';

function StaggeredList({ items }: { items: Item[] }) {
  return (
    <>
      {items.map((item, index) => (
        
          
        
      ))}
    
  );
}

Collapsing Header (Reanimated + ScrollHandler)

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  useAnimatedScrollHandler,
  interpolate,
  Extrapolation,
} from 'react-native-reanimated';

const HEADER_MAX = 200;
const HEADER_MIN = 80;

function CollapsingHeaderScreen() {
  const scrollY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (event) => {
      'worklet';
      scrollY.value = event.contentOffset.y;
    },
  });

  const headerStyle = useAnimatedStyle(() => ({
    height: interpolate(
      scrollY.value,
      [0, HEADER_MAX - HEADER_MIN],
      [HEADER_MAX, HEADER_MIN],
      Extrapolation.CLAMP,
    ),
  }));

  const titleStyle = useAnimatedStyle(() => ({
    opacity: interpolate(scrollY.value, [0, 60], [1, 0], Extrapolation.CLAMP),
    transform: [{
      scale: interpolate(scrollY.value, [0, 60], [1, 0.8], Extrapolation.CLAMP),
    }],
  }));

  return (
    <>
      
        Feed
      
      
        {/* Content */}
      
    
  );
}

Bottom Sheet (Gorhom v5)

import BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet';
import { useMemo, useRef } from 'react';

function MapScreen() {
  const sheetRef = useRef(null);
  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);

  return (
    <>
      
      
        
          {/* Sheet content */}
        
      
    
  );
}

Gorhom v5 uses Reanimated v4 + Gesture Handler v2 natively. Velocity-based dismiss is built in.

Swipe-to-Dismiss Card (Gesture Handler v2)

import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue, useAnimatedStyle, withSpring, runOnJS,
} from 'react-native-reanimated';

function SwipeCard({ onDismiss }: { onDismiss: () => void }) {
  const translateX = useSharedValue(0);
  const DISMISS_THRESHOLD = 150;

  const pan = Gesture.Pan()
    .onUpdate((e) => {
      'worklet';
      translateX.value = e.translationX;
    })
    .onEnd((e) => {
      'worklet';
      if (Math.abs(e.translationX) > DISMISS_THRESHOLD || Math.abs(e.velocityX) > 800) {
        translateX.value = withSpring(e.translationX > 0 ? 500 : -500, { damping: 20 });
        runOnJS(onDismiss)();
      } else {
        translateX.value = withSpring(0, { damping: 20, stiffness: 300 });
      }
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { rotate: `${translateX.value / 20}deg` },
    ],
    opacity: interpolate(Math.abs(translateX.value), [0, 200], [1, 0.5]),
  }));

  return (
    
      
        {/* Card content */}
      
    
  );
}

List Performance — FlashList, Always

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

 }
  estimatedItemSize={88}
  keyExtractor={(item) => item.id}
  getItemType={(item) => item.type}  // Critical for heterogeneous lists
/>

Rules:

  • React.memo every list item (React Compiler now default in SDK 54 — handles this automatically for new projects)
  • Pass primitives to items, not objects (userId={user.id} not user={user})
  • Stable callbacks — useCallback for onPress handlers passed to items
  • estimatedItemSize is required — use average height across item types
  • getItemType when items have different layouts — prevents recycling mismatches

Performance comparison:

| Component | 5000-item load | Scroll FPS | Memory | |---|---|---|---| | ScrollView | 1-3s freeze |


Generate BlurHash on the server when images are uploaded. The hash is 20-30 characters — embed in API responses.

---

## Loading States — Skeleton, Never Spinner

```tsx
import { Skeleton } from 'moti/skeleton';
import { MotiView } from 'moti';

function FeedItemSkeleton() {
  return (
    
      
      
        
        
      
    
  );
}

// In the screen
function FeedScreen() {
  const { data, isLoading } = useQuery(feedQuery);

  if (isLoading) {
    return (
       }
        estimatedItemSize={72}
      />
    );
  }

  return ;
}

Native Menus — Zeego (Not JS Overlays)

import * as ContextMenu from 'zeego/context-menu';

  
    
  
  
     sharePost(post.id)}>
      Share
      
    
     deletePost(post.id)} destructive>
      Delete
      
    
  

Zeego renders native UIMenu on iOS and PopupMenu on Android. Never build a custom JS menu component.


Navigation — Defer Heavy Work Past Transitions

import { useFocusEffect } from 'expo-router';
import { InteractionManager } from 'react-native';

export default function FeedScreen() {
  useFocusEffect(
    useCallback(() => {
      const task = InteractionManager.runAfterInteractions(() => {
        fetchFeedData();
        initializeAnalytics();
      });
      return () => task.cancel();
    }, [])
  );
}

Without this, data fetching during a navigation slide-in competes for JS thread time and causes jank.


Scroll — Never Track Position in State

// WRONG — re-renders entire tree on every scroll pixel
const [scrollY, setScrollY] = useState(0);
 setScrollY(e.nativeEvent.contentOffset.y)} />

// CORRECT — stays on UI thread, zero re-renders
const scrollY = useSharedValue(0);
const handler = useAnimatedScrollHandler({
  onScroll: (event) => {
    'worklet';
    scrollY.value = event.contentOffset.y;
  },
});

State Architecture

┌─────────────────────────────────────┐
│  Server State: TanStack Query       │  API data, cached + persisted to MMKV
│  (offline-first via MMKV persister) │
├─────────────────────────────────────┤
│  Client State: Zustand              │  Auth, settings, UI preferences
│  (persisted to MMKV)               │
├─────────────────────────────────────┤
│  UI State: Jotai atoms              │  Fine-grained: modals, filters, toggles
│  (ephemeral, not persisted)         │
├─────────────────────────────────────┤
│  Animation State: Reanimated        │  Shared values on UI thread
│  (never in React state)             │
└─────────────────────────────────────┘

Zustand + MMKV persistence:

import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { storage } from '@/lib/storage';

const mmkvStorage = createJSONStorage(() => ({
  getItem: (name) => storage.getString(name) ?? null,
  setItem: (name, value) => storage.set(name, value),
  removeItem: (name) => storage.delete(name),
}));

export const useAuthStore = create(
  persist(
    (set) => ({
      token: null as string | null,
      user: null as User | null,
      setAuth: (token: string, user: User) => set({ token, user }),
      clearAuth: () => set({ token: null, user: null }),
    }),
    { name: 'auth-storage', storage: mmkvStorage }
  )
);

Native iOS/Swift — Quick Reference

@Observable (iOS 17+) — NOT ObservableObject

@Observable
@MainActor
final class FeedViewModel {
    var posts: [Post] = []
    var isLoading = false

    func loadPosts() async {
        isLoading = true
        posts = try? await PostService.shared.fetchFeed() ?? []
        isLoading = false
    }
}

// View — no @StateObject, no @ObservedObject needed
struct FeedView: View {
    @State private var viewModel = FeedViewModel()
    var body: some View {
        List(viewModel.posts) { PostRow(post: $0) }
            .task { await viewModel.loadPosts() }
    }
}

Navigation (matche

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.