LS009 — Persistencia de sesión y mouth gate
Build: BasicPX-Win64-Shipping.exe — sello Apr 22 2026 01:13 (aparece en la fila de encabezado del debug overlay cuando lo activan).
Para: equipo de backend y CI/CD de Mindlabs.
Qué es esto: el build que van a recibir tiene tres clases de cambios: (1) fixes de lip-sync bajo presión de emociones (LS-009), (2) una expansión grande del protocolo TCP que no estaba disponible en la release anterior, (3) logs de Shipping habilitados para que podamos darles soporte real cuando algo pase en la nube. Acá abajo está todo lo que cambió y cómo aprovecharlo desde su backend.
Nota sobre el nombre del exe: BasicPX.exe y BasicPX-Win64-Shipping.exe son el nombre transitorio del binario. El proyecto consolidó varias piezas en un único demo y todavía arrastra ese naming — en próximos builds puede cambiar. Para ustedes es el mismo proceso; solo importa la línea de lanzamiento.
1. Resumen ejecutivo
Sección titulada «1. Resumen ejecutivo»| Tema | Qué tienen que hacer |
|---|---|
| Launcher del proceso | Cambiar BasicPX.exe por Run-Cloud.bat en el CI/CD. Una línea. |
| Protocolo TCP | Nada obligatorio. El esquema JSON y el framing binario no cambiaron — lo que existe adentro del protocolo creció: nuevas microexpresiones, nuevas emociones, stop/reset con targets finos, config con ~50 claves en runtime, look_at con modos. Sección 3.5 y 4. |
| Fix de lip-sync | Nada. El pipeline ahora aguanta emociones en ráfaga durante el habla sin trabarse. Sección 3.1 y 3.2. |
| Logs en Shipping | Nada obligatorio, pero conviene saber que ahora existen — el build Shipping genera %LOCALAPPDATA%\BasicPX\Saved\Logs\BasicPX.log utilizable para soporte. Sección 3.6. |
| Defaults cloud horneados | Nada. Ya quedaron en el paquete: 30 FPS, 4-8 Mbps, 540×960, chunk lip-sync 640, threads ONNX 2/1. Sección 3.3. |
El único cambio en pipeline es el launcher. Todo el resto es capacidad nueva que pueden usar cuando quieran.
2. Cambio obligatorio en el CI/CD
Sección titulada «2. Cambio obligatorio en el CI/CD»El pipeline seguramente lanza algo así:
...\package\Windows\BasicPX.exe -PixelStreamingURL=ws://signaling:80 <otros args>Después
Sección titulada «Después»Reemplazar BasicPX.exe por Run-Cloud.bat:
...\package\Windows\Run-Cloud.bat -PixelStreamingURL=ws://signaling:80 <otros args>Listo. Los argumentos extra se reenvían al exe vía %*. Si el wrapper no está en el paquete, la ejecución falla con exit code 2 y el mensaje [Run-Cloud] ERROR: BasicPX.exe not found — sirve como smoke signal del CI/CD.
Qué aplica el wrapper por ustedes
Sección titulada «Qué aplica el wrapper por ustedes»-RenderOffScreen— renderiza a textura GPU sin monitor. Obligatorio en EC2 headless; evita el clásico “no desktop” al startup.-ForceRes -ResX=540 -ResY=960— half-portrait HD fijo. Match con el budget de bitrate de PixelStreaming que dejamos horneado.-NoSound— no usa hardware de audio local (las EC2 no tienen). El audio sale por WebRTC como siempre.-AvatarPort=4500— puerto TCP default donde se conecta su Director. Si usan otro puerto, lo pasan con-AvatarPort=<N>desde el CI/CD.
Qué no mete el wrapper
Sección titulada «Qué no mete el wrapper»-PixelStreamingURL=...— valor por deployment, va del lado de ustedes.- Cualquier flag custom que ya vienen pasando (se reenvían tal cual).
3. Qué cambió en el avatar
Sección titulada «3. Qué cambió en el avatar»3.1 El lip-sync aguanta emociones en ráfaga (LS-009)
Sección titulada «3.1 El lip-sync aguanta emociones en ráfaga (LS-009)»Antes: si el backend mandaba varios comandos emotion seguidos mientras el avatar estaba hablando (por ejemplo a menos de 500 ms entre comandos), el pipeline de lip-sync se trababa visiblemente — la boca se abría y quedaba un instante más abierta antes de cerrar. No-determinístico, correlacionado con el volumen de emociones.
Ahora: el pipeline de lip-sync quedó desacoplado del evento de emoción durante el habla. Los comandos de emoción en ráfaga se resuelven como transiciones de estado puras, sin interrumpir el pipeline. La cara de emoción (cejas, ojos, mejillas) sigue aplicándose; la boca queda propiedad exclusiva del modelo ONNX mientras hay audio.
Impacto en backend: ninguno. Pueden mandar emociones a la frecuencia que quieran.
3.2 Aislamiento de curvas en zona de boca (LS-009b)
Sección titulada «3.2 Aislamiento de curvas en zona de boca (LS-009b)»Durante el habla activa, el avatar ahora corta las curvas de articulador labial que vienen de la emoción (jaw open, jaw forward, mouth close, mouth pucker, mouth funnel, mouth roll, etc.) para que no se sumen sobre la salida del modelo ONNX. Las señales estructurales de emoción (smile, frown, press) siguen aplicándose y se notan.
Impacto en backend: ninguno. Las emociones se ven un poco menos “exageradas en la boca” durante el habla, pero el lip-sync queda visiblemente más limpio.
3.3 Defaults cloud horneados en el build
Sección titulada «3.3 Defaults cloud horneados en el build»Estos valores ya están en el paquete Shipping y no requieren override desde el lado de ustedes:
| Parámetro | Valor horneado | Por qué |
|---|---|---|
FPS de render (t.MaxFPS) | 30 | Seguro para co-host de varios avatares en una sola GPU EC2 |
| FPS objetivo WebRTC | 30 | Match del cap de render |
| Bitrate inicial WebRTC | 4 Mbps | Valor razonable para half-portrait HD |
| Bitrate mínimo WebRTC | 0.5 Mbps | Piso en congestión |
| Bitrate máximo WebRTC | 8 Mbps | Techo para la resolución elegida |
| Keyframe interval | 60 frames (= 2 s a 30 FPS) | Recuperación más rápida ante packet loss |
| Lip-sync chunk size | 640 samples (40 ms @ 16 kHz) | Subimos el chunk para bajar CPU en EC2 — costo: ~30 ms más de latencia de boca, invisible al usuario |
| Lip-sync intra-op threads | 2 | Paralelismo interno ONNX por inferencia. Más alto no ayudó en T4/A10G |
| Lip-sync inter-op threads | 1 | Serial entre inferencias — evita contención con el render |
Si quieren sobreescribir alguno por deployment, el CI/CD puede seguir pasando argumentos de línea de comando de UE. Para el chunk de lip-sync:
Run-Cloud.bat -PixelStreamingURL=ws://... -LipSyncChunkSize=320Para los threads no hay flag de comando; se tocan en caliente vía TCP (sección 4.4).
3.4 Warnings de diagnóstico en runtime (opt-in, LS-009c)
Sección titulada «3.4 Warnings de diagnóstico en runtime (opt-in, LS-009c)»El avatar mantiene ahora un ring buffer de warnings visible en el debug overlay. No hace falta prenderlo para operación normal, pero sirve cuando QA o soporte tienen que investigar algo puntual.
Debug overlay default: OFF — los deployments de producción nunca muestran UI de diagnóstico al usuario final. Tres formas de activarlo:
- Al lanzar (recomendado para sesiones de QA): agregar
-DebugOverlayal comando.Run-Cloud.bat -PixelStreamingURL=ws://... -DebugOverlay - En runtime por TCP:
{"type":"config","key":"debug_overlay","value":1} - En Blueprint:
UAvatarDebugOverlaySpawner::ShowDebugOverlay()— solo editor / builds custom.
Categorías de warnings que pueden aparecer:
| Categoría | Qué significa | Qué hacer |
|---|---|---|
[Emotion] | Llegó un comando de emoción durante habla activa. El sistema lo manejó bien; es informativo. | Nada — solo confirma que el evento pasó. |
[LipSync] | Se reconstruyó el generador ONNX. Normal en la primera frase; sospechoso a mitad de sesión. | Si lo ven a mitad de flujo, capturen logs y mándenlos. |
[Audio] | La cola de audio pasó de ~60 ms — la inferencia ONNX está corriendo atrás del stream. | Si se sostiene, la EC2 está con CPU starvation (síntoma multi-tenant). Escalar o bajar co-tenants. |
Los warnings salen abajo del overlay en texto ámbar. El ring buffer guarda los últimos 20.
3.5 Expansión del protocolo (importante — capacidades nuevas desde la release anterior)
Sección titulada «3.5 Expansión del protocolo (importante — capacidades nuevas desde la release anterior)»El framing binario y el top-level JSON ({"type": ...}) no cambiaron. Lo que creció es lo que el avatar sabe hacer cuando reciben cada comando. Resumen de lo nuevo:
Microexpresiones — 31 en total, antes había un subconjunto chico.
- 25 faciales con zonas
Brow/Eyes/Mouth/Jaw/Nose/Cheek/Compound— incluyen asimetrías (brow_raise_left,mouth_press_right,eye_squint_left, etc.), variantes sutiles (smile_slightvssmile_broad), compuestas (empathy,tension), y señales físicas (lip_bite,cheek_puff,chin_quirk). - 6 gestos de cabeza:
nod_small(8°),nod_large(15°),shake(12° yaw × 3 ciclos),tilt,tilt_left,tilt_right(10°). Se disparan con el mismo comandomicroexpression. - Lista completa en la referencia de la API del backend.
Emociones — 9 con aliases, antes 8 y sin aliases.
neutral/idle/default,happy/joy,sad/sadness,angry/anger,surprised/surprise,disgusted/disgust,fearful/fear,thinking/pensive,excited/very_happy/thrilled/elated.- Todos los aliases son case-insensitive.
stop y reset con targets finos — antes era stop global.
- Targets válidos:
speaking,emotion,expression,gesture,gaze,head,moving(composite de gaze+gesture+head), o vacío (todo). stopcongela en el estado actual.resetvuelve a default.
look_at con modos de mirada — antes solo cabeza+ojos coordinados.
- Modos:
head_only,realistic(default),eyes_only. - La forma mínima
{"type":"look_at","x":...,"y":...}entra por fast-path sin overhead de JSON — soporta 60 Hz de streaming sin problema. - El comando pisa al FSM de gaze autónomo por
auto_gaze_override_durationsegundos (default 5s, configurable).
Modo escucha (listen) — antes no estaba.
- Ancla la mirada a cámara y corre micro-secuencias simulando atención.
- Auto-exit cuando llega audio nuevo (default on).
- Se sale manualmente con
{"type":"config","key":"listening_mode","value":0}.
Máquina de estados expuesta — 4 estados: Idle, Speaking, Emoting, Transitioning. Transiciones relevantes para el backend:
- Cualquier → Speaking: llegada del primer chunk de audio.
- Speaking → Idle: sin audio por
SilenceTimeoutSeconds(default 2s). - Dentro de Speaking: si hay un gap de audio >
NewUtteranceGapSeconds(default 0.5s), se recicla la sesión ONNX — esto es lo que permite que cada utterance arranque “limpia” sin arrastrar contexto de la anterior.
Comando config con ~50 claves en runtime — antes era una lista muy corta. Las nuevas categorías que vale la pena conocer:
- Influencia de emoción en boca (per-emotion, per-state):
emotion_mouth_speaking,emotion_mouth_idle,emotion_mouth_override_speaking,emotion_mouth_override_idle, blend speeds. - Microexpresiones globales:
microexpression_intensity_scale,head_gesture_intensity_scale,head_rotation_interp_speed,anim_gesture_head_return_speed. - Idle variation:
idle_variation_enabled, head sway amplitud/período, blink enable/intervals/duration. - Idle behaviors (scheduler Poisson de “signos de vida” — swallows, brow quirks, nostril flares):
idle_behaviors_enabled, mean/min/max intervals, intensity scale, energy variance/period. Toggle por categoría:idle_category_enabledcon"category":"throat"|"nose"|"mouth"|"brow"|"headtilt"|"compound". - Gaze:
look_at_head_speed,look_at_eye_speed,look_at_smoothness,look_at_camera_while_speaking,autonomous_gaze_enabled,auto_gaze_override_duration,listening_mode. - Head idle baseline:
head_idle_baseline_enabled,head_idle_baseline_max_deg. - ZenBlink (plugin de blink/head-movement):
zenblink_idle_strength,zenblink_speaking_strength. - Lip-sync:
lipsync_chunk_size,lipsync_max_buffer,lipsync_mood,lipsync_mood_intensity,lipsync_lookahead_ms,lipsync_output_type,lipsync_intra_threads,lipsync_inter_threads. - Engine/render:
debug_overlay,max_fps,ray_tracing,resolution(porcentaje o{width,height}),quality_preset(server_t4/server_a10g/local_dev),cvar(CVar arbitraria con allowlist de ~30 nombres).
Referencia completa de cada clave (tipos, defaults, rangos, campos extra): la referencia de la API del backend.
Presets de calidad por GPU — nuevo. Un solo comando aplica un batch de CVars para la clase de GPU que estén usando:
{"type":"config","key":"quality_preset","value":"server_t4"}{"type":"config","key":"quality_preset","value":"server_a10g"}{"type":"config","key":"quality_preset","value":"local_dev"}CVar passthrough con allowlist — nuevo. Pueden tocar cualquier CVar de UE en runtime siempre que esté en la lista permitida (ray tracing, Lumen, TSR, TAA, screen percentage, PixelStreaming bitrate, etc.). Todo lo que no esté en la lista se rechaza y se loguea.
3.6 Logs en Shipping habilitados (esto es nuevo, y no es trivial)
Sección titulada «3.6 Logs en Shipping habilitados (esto es nuevo, y no es trivial)»Las builds Shipping de Unreal por default son silenciosas — no escriben logs. Para este deployment habilitamos bUseLoggingInShipping = true en BasicPX.Target.cs, lo que significa que el build que van a correr en la nube escribe a %LOCALAPPDATA%\BasicPX\Saved\Logs\BasicPX.log (y su rotación) tal como lo haría un build de Development.
Por qué importa para ustedes:
- Si algo explota en la EC2, podemos darles un análisis post-mortem basado en evidencia, no especulación.
- Los warnings
[Emotion]/[LipSync]/[Audio]de la sección 3.4 se persisten al log además de aparecer en el overlay. Con el log en mano reconstruimos una sesión completa sin necesidad de repro en vivo. - Las transiciones de estado, los comandos recibidos, los rebuilds de generador ONNX, los timeouts de silence, el lifecycle del socket TCP — todo queda trazable.
Qué requirió de nuestro lado:
bUseLoggingInShipping=truedispara el chequeo[RequiresUniqueBuildEnvironment]de UE, que bloquea el uso del engine binario del Launcher. Para habilitarlo tuvimos que compilar Unreal Engine 5.7 desde el source, validarlo, y ensamblar el pipeline de packaging contra ese engine.- Hubo que verificar que el flush de logs sobreviviera a un exit abrupto en Shipping (que es donde más lo vamos a necesitar), tunear buffers, y confirmar que el overhead de logging no degradara el frame budget en T4/A10G bajo carga.
- El costo fue significativo en tiempo de ingeniería y planificación. No es un flag, es una línea de trabajo.
Lo que ustedes tienen que saber:
- Cuando abran un ticket con nosotros, adjunten el log. El sello de build del encabezado del archivo les confirma qué versión estaban corriendo.
- El log rota automáticamente; si la sesión fue larga, la pieza relevante puede estar en un archivo numerado (
BasicPX-backup-*.log). - Los logs pueden llegar a ser verbosos. Si mandan uno grande, compriman.
4. Cómo mandar comandos desde el backend
Sección titulada «4. Cómo mandar comandos desde el backend»4.1 Framing TCP
Sección titulada «4.1 Framing TCP»Cada frame en el socket es exactamente:
[1 byte Type] [4 bytes Length, little-endian int32] [Payload de Length bytes]Máximo de payload por frame: 10 MB (10_485_760 bytes). Frames más grandes se rechazan y la conexión se cierra.
Dos tipos de payload:
| Type | Payload | Uso |
|---|---|---|
0x00 | PCM crudo: 48 kHz, 16-bit signed, mono, little-endian | Audio al avatar para lip-sync |
0x01 | JSON UTF-8 | Comandos (emoción, microexpresión, gesto, mirada, config, etc.) |
Un solo cliente conectado a la vez. Si se conecta un segundo, el listener lo rechaza y loguea TCP: Second client rejected. Hagan reconnect con backoff exponencial — disconnects transitorios (restart, crash recovery) son esperables.
4.2 Helper de referencia en Python
Sección titulada «4.2 Helper de referencia en Python»import socket, struct, json
PKT_AUDIO = 0x00PKT_COMMAND = 0x01
def send_packet(sock, pkt_type, payload: bytes): header = struct.pack("<Bi", pkt_type, len(payload)) # 1 byte + int32 LE sock.sendall(header + payload)
def send_command(sock, cmd: dict): send_packet(sock, PKT_COMMAND, json.dumps(cmd).encode("utf-8"))
def send_audio_chunk(sock, pcm_bytes: bytes): send_packet(sock, PKT_AUDIO, pcm_bytes)
sock = socket.create_connection(("<host-cloud>", 4500), timeout=3.0)Si usan otro lenguaje, lo único que importa es el header <Bi> (byte + int32 little-endian) y el payload UTF-8 para JSON. Pseudocódigo:
function send_json_command(socket, command_dict): json_bytes = utf8_encode(json_serialize(command_dict)) type_byte = 0x01 length = little_endian_int32(len(json_bytes)) socket.send(byte(type_byte) + length + json_bytes)4.3 Comandos disponibles (Type 0x01)
Sección titulada «4.3 Comandos disponibles (Type 0x01)»emotion — estado sostenido. Valores: neutral, happy, sad, angry, surprised, disgusted, fearful, thinking, excited (más aliases).
{"type": "emotion", "name": "happy"}microexpression — gesto discreto con duración. 31 nombres disponibles (25 faciales + 6 de cabeza). intensity default 1.0, duration_ms default 300. Alias: el campo name también acepta expression.
{"type": "microexpression", "name": "brow_raise", "intensity": 0.8, "duration_ms": 500}{"type": "microexpression", "name": "nod_small", "intensity": 0.5, "duration_ms": 400}anim_gesture — montage de cuerpo/cabeza. Requiere que el Blueprint del personaje tenga el gesto mapeado (si no, no-op). intensity es play-rate multiplier (0.1 a 5.0).
{"type": "anim_gesture", "name": "wave", "intensity": 1.0}look_at — coordenadas normalizadas (0..1). La forma mínima usa fast-path:
{"type": "look_at", "x": 0.5, "y": 0.3}Con modo override:
{"type": "look_at", "x": 0.3, "y": 0.6, "mode": "eyes_only"}Modos: head_only, realistic, eyes_only. Case-insensitive.
stop — congela en el estado actual.
{"type": "stop"}{"type": "stop", "target": "speaking"}{"type": "stop", "target": "moving"}Targets: speaking / emotion / expression / gesture / gaze / head / moving / vacío (todo).
reset — vuelve a defaults. Mismos targets que stop.
{"type": "reset"}{"type": "reset", "target": "speaking"}listen — modo escucha. Auto-exit al recibir audio (default).
{"type": "listen"}Salida manual:
{"type": "config", "key": "listening_mode", "value": 0}config — cambios en runtime. Ver 4.4.
4.4 Configuración en vivo (claves más usadas)
Sección titulada «4.4 Configuración en vivo (claves más usadas)»Forma general: {"type":"config","key":<clave>,"value":<valor>}. Algunas claves requieren campos extra (emotion, category, name).
Lip-sync:
{"type":"config","key":"lipsync_chunk_size","value":320}{"type":"config","key":"lipsync_intra_threads","value":4}{"type":"config","key":"lipsync_mood","value":"happy"}{"type":"config","key":"lipsync_mood_intensity","value":0.8}Influencia de emoción en boca:
{"type":"config","key":"emotion_mouth_speaking","value":0.15}{"type":"config","key":"emotion_mouth_override_speaking","emotion":"surprised","value":0.40}Idle behaviors (signos de vida automáticos):
{"type":"config","key":"idle_behaviors_enabled","value":1}{"type":"config","key":"idle_behavior_mean_interval","value":5.0}{"type":"config","key":"idle_category_enabled","value":0,"category":"mouth"}Gaze:
{"type":"config","key":"look_at_head_speed","value":8.0}{"type":"config","key":"autonomous_gaze_enabled","value":0}{"type":"config","key":"auto_gaze_override_duration","value":10.0}Render / quality:
{"type":"config","key":"debug_overlay","value":1}{"type":"config","key":"quality_preset","value":"server_t4"}{"type":"config","key":"resolution","value":{"width":720,"height":1280}}{"type":"config","key":"cvar","name":"r.ScreenPercentage","value":75}Lista completa con tipos, rangos y defaults: la referencia de la API del backend.
4.5 Audio (Type 0x00)
Sección titulada «4.5 Audio (Type 0x00)»Formato: 48 kHz, 16-bit signed, mono, little-endian. No negociable.
CHUNK = 4096 # bytes (= 2048 samples = ~42 ms)for i in range(0, len(pcm), CHUNK): send_audio_chunk(sock, pcm[i:i+CHUNK])Si el TTS de ustedes devuelve 24 kHz o 16 kHz, upsampleen a 48 kHz antes de mandar. Si devuelve float32, conviertan a int16. Si devuelve MP3/AAC, decodifiquen primero. Chunks chicos (≤ 8 KB) bajan la latencia percibida; chunks grandes saturan la cola de audio y disparan el warning [Audio].
No hace falta mandar un comando “start speaking”. La llegada del primer frame de audio transiciona el avatar a Speaking automáticamente. Al dejar de mandar, vuelve a Idle después de SilenceTimeoutSeconds (default 2s). Si hay un gap interno > NewUtteranceGapSeconds (default 0.5s), el avatar recicla la sesión ONNX — esto permite encadenar múltiples utterances sin que el modelo arrastre contexto.
4.6 Ejemplo completo — “hola mundo” con emoción y microexpresión
Sección titulada «4.6 Ejemplo completo — “hola mundo” con emoción y microexpresión»sock = socket.create_connection(("<host-cloud>", 4500), timeout=3.0)
# 1. Emoción basesend_command(sock, {"type": "emotion", "name": "happy"})
# 2. Microexpresión disparada con el saludosend_command(sock, {"type": "microexpression", "name": "brow_raise", "intensity": 0.7, "duration_ms": 400})
# 3. Stream del audio TTS (ya convertido a PCM 48kHz/16-bit/mono/LE)for i in range(0, len(pcm), 4096): send_audio_chunk(sock, pcm[i:i+4096])
# 4. Al terminar, dejar al avatar en modo escuchasend_command(sock, {"type": "listen"})5. Checklist de verificación post-deploy
Sección titulada «5. Checklist de verificación post-deploy»Cuando desplieguen un build con Run-Cloud.bat en la línea de lanzamiento:
-
El proceso arranca sin ventana visible. Confirmen con el task manager que
BasicPX-Win64-Shipping.exeestá corriendo. Si aparece una ventana en el desktop de la EC2,-RenderOffScreenno se está aplicando — chequeen que el CI/CD esté invocando realmenteRun-Cloud.baty no el exe crudo. -
Puerto TCP 4500 bindeado. El Director de ustedes se conecta como siempre. El log de arranque dice
AvatarNetworkManager: Listening on port 4500. -
Stream WebRTC a 30 FPS. Fácil de verificar del lado cliente: el stream recibido debería anunciar 30 FPS. Si sigue en 60, algún override del deploy está pisando el default horneado.
-
Lip-sync estable bajo presión de emociones. Stress test: disparen
emotiona 2-5 Hz mientras hay audio. La boca tiene que cerrar completamente entre fonemas, sin artefacto de “trabada abierta”. Si todavía ven el lag viejo, chequeen que estén corriendo el build nuevo — el debug overlay muestra el sello de build en el encabezado. -
Panel de warnings se llena. Prendan el debug overlay; tendrían que ver
[LipSync] Generator rebuilt …como primer warning en la primera frase. -
El log existe. Verifiquen que
%LOCALAPPDATA%\BasicPX\Saved\Logs\BasicPX.logse esté escribiendo durante la sesión. Si no aparece, hay algo raro con el launcher — avísennos.
6. Comportamientos esperables (no son bugs)
Sección titulada «6. Comportamientos esperables (no son bugs)»-
Flips de estado
Speaking → Emoting → Speakingde 1 ms en los logs cuando llega una emoción durante el habla. Es el comportamiento nuevo correcto — la emoción se registra en la máquina de estados pero el pipeline de lip-sync no se interrumpe. -
Primera frase tiene un delay chico (~1-2 s) cuando se carga el generador ONNX por primera vez. Es el costo de inicialización; las frases siguientes reutilizan el generador y arrancan al toque. El warning
[LipSync] Generator rebuilt …marca ese momento. -
Debug overlay apagado por default. Se activa por sesión vía
-DebugOverlayo el comando de config TCP. Nunca visible al usuario final salvo que lo prendan explícito. -
t.MaxFPS=30viene como cvar en Shipping. Es el cap intencional. Tests locales en monitor de 60 Hz pueden ver 60 FPS efectivos por vsync — no afecta el deploy cloud donde no hay vsync. -
Gaps cortos de audio reciclan la sesión ONNX. Si mandan utterances separadas por > 500 ms de silencio, el modelo arranca una sesión nueva para el próximo chunk. Esto es el mecanismo que hace que cada utterance sea “limpia”.
7. Consultas / soporte
Sección titulada «7. Consultas / soporte»Si pegan algún tema, los log captures son más útiles que las descripciones. Manden:
- El sello de build que aparece en el encabezado del debug overlay (ej.
Apr 22 2026 01:13). - Contenido de
%LOCALAPPDATA%\BasicPX\Saved\Logs\BasicPX.log(Windows EC2) de la sesión afectada. Si la sesión fue larga, revisen también losBasicPX-backup-*.logrotados. - Pasos de reproducción si el issue es determinístico.
Para los templates completos de reporte de bugs / pedido de features / submisión de logs, más la matriz de canales de contacto, ver Soporte. Los canales que acordamos en el contrato (escalación P0, Slack dedicado) tienen prioridad sobre los placeholders de esa página.