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...
}
});
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,
}
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);
}
Navigation Flow
- User opens scanner
- Points camera at object OR scans QR code
- Presses Pokéball button (manual) or QR is auto-detected
- Color is extracted and analyzed
- Pokémon match is found
- Navigates to Details screen with
pokemonId
See ScannerScreen.js:76 for navigation implementation.