Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/soymatudev/Pokedex-Fleek/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Camera Scanner is the core feature of PokéDex Fleek, enabling users to identify Pokémon by scanning real-world objects. It uses react-native-vision-camera v4 for camera access, frame processing, and QR code scanning capabilities.

Key Features

Camera Integration

The scanner uses react-native-vision-camera with the back camera:
import { Camera, useCameraDevice, useCodeScanner } from 'react-native-vision-camera';

const device = useCameraDevice('back');
const cameraRef = useRef(null);
The camera component is only active when the screen is focused:
const isFocused = useIsFocused();

{isFocused && (
  <Camera
    ref={cameraRef}
    codeScanner={codeScanner}
    device={device}
    isActive={true}
    style={StyleSheet.absoluteFill}
    photo={true}
  />
)}

QR Code Scanning

The scanner supports QR codes and EAN-13 barcodes for automatic Pokémon detection:
const codeScanner = useCodeScanner({
  codeTypes: ['qr', 'ean-13'],
  onCodeScanned: async (codes) => {
    if (isProcessing || detectedPokemon || codes.length === 0) return;
    
    setIsProcessing(true);
    const id = codes[0].value;
    
    // Capture photo for color analysis
    const photo = await cameraRef.current.takePhoto({
      flash: 'off',
      skipMetadata: true
    });
    
    // Process color...
  }
});

Manual Scan Button

The manual scan button features a custom Pokéball design:
const handleManualScan = async () => {
  if (isProcessing) return;
  Vibration.vibrate(70);
  setIsProcessing(true);

  try {
    const photo = await cameraRef.current.takePhoto({ 
      flash: 'off', 
      skipMetadata: true 
    });
    
    const result = await ImageColors.getColors(photo.path, { 
      fallback: '#000000' 
    });
    
    const detectedHex = result.platform === 'android' 
      ? result.dominant 
      : result.background;
    
    const hue = hexToHue(detectedHex);
    
    // Find matching Pokémon...
  } catch (error) {
    console.error(error);
    Vibration.vibrate(400);
    setIsProcessing(false);
  }
};

UI Components

Reticle Overlay

The scanner displays a centered reticle for targeting:
<View style={styles.reticleContainer}>
  <View style={styles.reticle}>
    <View style={styles.reticleDot} />
  </View>
  <Text style={styles.reticleText}>CENTRAR OBJETIVO</Text>
</View>
Styles:
reticle: {
  width: 80,
  height: 80,
  borderRadius: 40,
  borderWidth: 2,
  borderColor: 'rgba(255, 255, 255, 0.8)',
  borderStyle: 'dashed',
  alignItems: 'center',
  justifyContent: 'center',
},
reticleDot: {
  width: 6,
  height: 6,
  backgroundColor: theme.colors.primary,
  borderRadius: 3,
}

Pokéball Scan Button

The manual scan button mimics a Pokéball:
<TouchableOpacity
  style={[
    styles.pokeballButton,
    isProcessing && { borderColor: theme.colors.primary, elevation: 20 }
  ]}
  onPress={handleManualScan}
  disabled={isProcessing}
>
  <View style={[
    styles.pokeballInnerRing,
    isProcessing && { borderColor: '#fff' }
  ]}>
    {isProcessing ? (
      <ActivityIndicator color="#333" />
    ) : (
      <View style={styles.pokeballCenterBtn} />
    )}
  </View>
</TouchableOpacity>
<Text style={styles.scanBtnLabel}>
  {isProcessing ? "ANALIZANDO..." : "ESCANEAR ADN"}
</Text>
Styles:
pokeballButton: {
  width: 80,
  height: 80,
  borderRadius: 40,
  backgroundColor: '#fff',
  borderWidth: 4,
  borderColor: '#333',
  elevation: 10,
},
pokeballInnerRing: {
  width: 65,
  height: 65,
  borderRadius: 32.5,
  borderWidth: 15,
  borderColor: '#ff1c1c', // Pokéball red
}

Permission Handling

The scanner requests camera permissions on mount:
useEffect(() => {
  (async () => {
    const status = await Camera.requestCameraPermission();
    setHasPermission(status === 'granted');
  })();
}, []);

if (!hasPermission) {
  return (
    <View style={styles.center}>
      <Text style={styles.errorText}>Dexter necesita permisos de cámara</Text>
      <TouchableOpacity onPress={() => Linking.openSettings()} style={styles.backButton}>
        <Text style={{ color: 'white' }}>ABRIR AJUSTES</Text>
      </TouchableOpacity>
    </View>
  );
}

Frame Processing

The scanner captures frames and extracts dominant colors using react-native-image-colors:
const photo = await cameraRef.current.takePhoto({
  flash: 'off',
  skipMetadata: true
});

const result = await ImageColors.getColors(photo.path, { 
  fallback: '#000000' 
});

const detectedHex = result.platform === 'android' 
  ? result.dominant 
  : result.background;

Color Matching

After extracting the dominant color, the scanner converts it to HSL hue and matches against the Pokémon database:
const hue = hexToHue(detectedHex);

const match = Object.values(POKEMON_DB).find(p =>
  hue >= p.colorRange.hueMin && hue <= p.colorRange.hueMax
);

if (match) {
  setDetectedPokemon(match);
  setTimeout(() => {
    navigation.navigate('Details', { pokemonId: match.id });
  }, 1000);
}

Haptic Feedback

The scanner provides haptic feedback for user interactions:
// Single vibration on button press
Vibration.vibrate(70);

// Success pattern on match
if (match) {
  Vibration.vibrate([0, 100, 50, 100]);
} else {
  Vibration.vibrate(400);
}
  1. User opens scanner
  2. Points camera at object OR scans QR code
  3. Presses Pokéball button (manual) or QR is auto-detected
  4. Color is extracted and analyzed
  5. Pokémon match is found
  6. Navigates to Details screen with pokemonId
See ScannerScreen.js:76 for navigation implementation.