Normalización Multiplataforma: Guía para Evitar Errores de Case Sensitivity
Uno de los bugs más insidiosos en desarrollo multiplataforma es la diferencia en cómo los sistemas operativos manejan mayúsculas en nombres de archivos. Esta guía documenta las convenciones y herramientas para evitarlo desde el principio.
El problema: Windows vs Linux/Android/Mac
Cuando desarrollas un juego o app que corre en múltiples plataformas, te encuentras con una diferencia fundamental en cómo los sistemas operativos tratan los nombres de archivos:
- Windows: No es case-sensitive.
Icon.pngeicon.pngson el mismo archivo. - Linux, Mac, Android, iOS: Sí son case-sensitive.
Icon.pngeicon.pngson archivos distintos. Si tu código buscaicon.pngpero el archivo se llamaIcon.png, no lo encuentra.
El resultado típico: el juego funciona perfectamente en tu máquina Windows, pero falla al sincronizarlo a Android o subirlo a un servidor Linux. El error es silencioso: imagen rota, icono que no aparece, pantalla de carga genérica. Sin mensaje de error claro.
La regla de oro: siempre minúsculas
La solución es adoptar una convención estricta y sin excepciones: todos los nombres de archivos en minúsculas. Funciona en Windows, Linux, Mac, Android e iOS.
| ❌ Incorrecto | ✅ Correcto | Razón |
|---|---|---|
Icon.png |
icon.png |
Linux/Android lo necesita en minúsculas |
MainBackground.webp |
main-background.webp |
Guiones son más legibles que camelCase en archivos |
AudioMaster.js |
audio-master.js |
Consistencia: archivos siempre en kebab-case |
GameData.JSON |
game-data.json |
Extensiones también en minúsculas |
MY_CONFIG.txt |
my-config.txt |
Guiones, no underscores, para consistencia |
En el código, las referencias a archivos también deben estar en minúsculas:
// Incorrecto — depende de si el archivo es Icon.png o icon.png
const icon = document.createElement("img");
icon.src = "images/Icon.png";
// Correcto — siempre minusculas
const icon2 = document.createElement("img");
icon2.src = "images/icon.png";
Estructura de carpetas estándar
Las carpetas también deben seguir la misma convención. Esta es la estructura recomendada para un proyecto web/app multiplataforma:
proyecto/
├── www/ ← contenido web
│ ├── index.html
│ ├── assets/
│ │ ├── images/
│ │ │ ├── icon.png
│ │ │ ├── main-background.webp
│ │ │ └── ui-buttons.webp
│ │ ├── audio/
│ │ │ ├── theme-music.ogg
│ │ │ └── sfx-click.ogg
│ │ ├── css/
│ │ │ └── style.css
│ │ └── js/
│ │ ├── audio-master.js
│ │ └── app.js
│ └── data/
│ └── game-config.json
│
├── android/ ← recursos específicos Android
│ └── res/
│ ├── mipmap-hdpi/
│ ├── mipmap-xhdpi/
│ └── mipmap-anydpi-v26/
│ └── ic-launcher.xml
│
└── docs/
└── naming-conventions.md
Caso especial: iconos de aplicación en Android
Los iconos de Android son especialmente problemáticos porque requieren múltiples archivos en múltiples directorios con nombres muy específicos. La estructura correcta:
android/res/
├── mipmap-mdpi/
│ ├── ic-launcher.png (192×192 px)
│ └── ic-launcher-foreground.png
├── mipmap-hdpi/
│ ├── ic-launcher.png (288×288 px)
│ └── ic-launcher-foreground.png
├── mipmap-xhdpi/
│ ├── ic-launcher.png (384×384 px)
│ └── ic-launcher-foreground.png
├── mipmap-xxhdpi/
│ ├── ic-launcher.png (512×512 px)
│ └── ic-launcher-foreground.png
└── mipmap-anydpi-v26/
└── ic-launcher.xml
El archivo ic-launcher.xml debe contener:
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic-launcher-background" />
<foreground android:drawable="@mipmap/ic-launcher-foreground" />
</adaptive-icon>
- Olvidar copiar
ic-launcher-foreground.pnga TODOS los directorios mipmap-* - Nombrar el archivo
ic_launcher.png(underscore) en lugar deic-launcher.png(guión) - El XML referencia
ic_launcher_foregroundpero el archivo se llamaic-launcher-foreground.png - El archivo existe en mipmap-mdpi pero no en mipmap-hdpi (Android busca en la densidad apropiada)
Rutas en código: relativas y separadores
Otro problema de compatibilidad es el separador de ruta. En web y Linux se usa /; en Windows se usa \. En código JavaScript para web, siempre usa forward slash:
// Correcto — forward slash siempre en web
const imagePath = "assets/images/icon.png";
const audioPath = "assets/audio/theme-music.ogg";
// Incorrecto — backslash de Windows no funciona en URLs
// const imagePath = "assets\images\icon.png"; // Falla en navegador
// En RPG Maker, las rutas internas se normalizan automaticamente
ImageManager.loadBitmap("img/pictures/", "my-background");
Sincronización con Capacitor/Android
Si usas Capacitor para compilar tu app web a Android, hay problemas adicionales. Cuando ejecutas capacitor sync, algunos archivos pueden no copiarse si:
- Están en
.gitignore(Capacitor no los ve) - No están dentro de la carpeta
www/ - El nombre cambió de mayúsculas a minúsculas y git no detectó el cambio
Script de verificación post-sincronización:
#!/bin/bash
# verify-sync.sh
files_to_check=(
"android/app/src/main/assets/www/index.html"
"android/app/src/main/assets/www/assets/images/icon.png"
"android/res/mipmap-hdpi/ic-launcher.png"
"android/res/mipmap-hdpi/ic-launcher-foreground.png"
"android/res/mipmap-xhdpi/ic-launcher.png"
"android/res/mipmap-xhdpi/ic-launcher-foreground.png"
)
for file in "${files_to_check[@]}"; do
if [ -f "$file" ]; then
echo "✅ $file"
else
echo "❌ FALTA: $file"
fi
done
Convenciones de nomenclatura completas
| Tipo | Convención | Ejemplo |
|---|---|---|
| Variables JS | camelCase | playerHealth, mainBackground |
| Constantes JS | UPPER_SNAKE_CASE | CARD_WIDTH, MAX_PLAYERS |
| Clases JS | PascalCase | GameState, AudioMaster |
| Archivos de código | kebab-case | audio-master.js, game-state.js |
| Imágenes | kebab-case | main-background.png, ui-button.webp |
| Audio | kebab-case | theme-music.ogg, sfx-click.ogg |
La regla simple: camelCase para código, kebab-case para archivos. Nunca mezcles.
Checklist de verificación antes de publicar
- Todos los nombres de archivos en minúsculas
- Guiones en lugar de underscores o camelCase en nombres de archivo
- Todas las referencias en código coinciden exactamente con los nombres de archivo
- En Android, iconos presentes en todos los directorios mipmap-*
- El XML de Android referencia correctamente los iconos
- Rutas en código usan forward slash
/, nunca backslash\ - Después de sincronizar, ejecutar el script de verificación
- Probar en al menos un navegador web y una plataforma móvil
La normalización multiplataforma no es glamurosa, pero es el tipo de decisión que evita horas de debugging frustrante. Invertir 30 minutos al inicio del proyecto en establecer estas convenciones ahorra 10 horas más tarde.
Regla final: Cuando dudes, usa minúsculas y guiones. Nunca falla.