# Web (TeaVM/WebGL) y sus limitaciones reales

> El app compilado a JS vía TeaVM corriendo en un canvas WebGL2 — y lo que NO funciona.

Source: https://crossfly.dev/es/docs/platforms/web-teavm — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Web (TeaVM/WebGL) 🌐

**La página más honesta de la sección.** El destino web (módulo `web`, `WebLauncher`) compila el app a
**JavaScript vía TeaVM** y lo corre en un `<canvas>` **WebGL2** (backend `gdx-teavm`). **No es GWT** y
**no** es un webview embebido: es el **propio app** corriendo en el navegador.

## Build y servir
```bash
gradlew :web:webBundle       # (alias: dist)
```
Genera `web/build/webapp/` con `index.html`, `web.js`, `scripts/howler.js`, `gdx.wasm.js`, y
`assets/` + `assets.txt`. Sírvelo localmente:
```bash
cd web/build/webapp && python -m http.server 8080
# abre http://127.0.0.1:8080/index.html
```
El `WebLauncher` hace `new TeaApplication(new Main(true, cmdline), config)`.

## ⚠️ Lo que NO funciona (es *stub*)
En la web, `PlatformUtilsWeb` implementa la mayoría de los recursos como *stub* — la llamada existe pero **no
hace nada útil**:
| Función | Comportamiento en la web |
|---|---|
| `WebContainer` | `createWebView()` devuelve **`null`** |
| GPS / ubicación | *stub* (sin fix) |
| Bluetooth / radios | *stub* (`WirelessState.UNSUPPORTED`) |
| Biometría | `AuthResult.ERROR` "Not supported" |
| Voz (TTS/STT) | `voiceToText` → `onError` |
| Mapas nativos | no soportado |
| Vibración / batería | *stub* |
| **Persistencia de archivos** | `Device.homeFolder = null` |

> Como `crossfly-lib` (JNI) **no se carga en WebGL** (`Main.create()` omite el `SharedLibraryLoader`
> en el destino WebGL), todo lo que depende de nativo cae a los *stubs* de arriba.

## Lo que SÍ FUNCIONA
- **Renderizar la UI** completa (es el app real en el canvas WebGL2).
- **Abrir URL externa / marcar**: `PlatformUtils.instance.view(url)` / `dial(numero)` (vía
  `Gdx.net.openURI`).
- HTTP con **restricciones** (CORS; `Utils.getRemoteFile` devuelve `null` en caso de fallo).

## Patrón obligatorio: detecta y cae al fallback
```java
if (PlatformUtils.instance.createWebView() != null) {
   // Android/iOS/Desktop: webview embebido
} else {
   PlatformUtils.instance.view(url);   // Web: abre en una nueva pestaña
}
```
Y comprueba `Device.homeFolder == null` antes de intentar persistir un archivo en la web.

## Buenas prácticas
- **Deshabilita/adapta** los recursos de dispositivo en la web (no dejes botones que no hacen nada).
- Persistencia en la web: usa lo que esté disponible en tu build (no cuentes con `homeFolder`).
- Prueba sirviendo el bundle estático localmente antes de hospedarlo.

## Errores comunes
- Asumir `WebContainer`/GPS/biometría en la web (son *stub*).
- Intentar `Device.homeFolder + "arquivo"` en la web (`homeFolder` es `null` → NPE).

## Ver también
- [Integración nativa](/docs/platforms/native-integration) · [Matriz de plataformas](/docs/platforms/overview)
