Este documento contiene la especificación de diseño visual, flujo de usuario y arquitectura técnica para la Progressive Web App (PWA) de Demostración de NumChat. El objetivo de este diseño es permitir que cualquier desarrollador web front-end implemente un prototipo funcional en menos de 48 horas que funcione 100% offline (Modo Avión) y simule la transmisión acústica/ultrasónica del protocolo semántico de 4 bytes.
A diferencia de las conexiones tradicionales (Bluetooth, Wi-Fi Direct) que requieren un proceso de emparejamiento (pairing/handshake), NumChat funciona bajo un modelo descentralizado de difusión pura:
La PWA consta de una sola página reactiva (Single Page Application) con pestañas deslizantes para alternar entre los roles de Emisor (A) y Receptor (B).
+-------------------------------------------------------------+
| NUMCHAT |
| [ MODO AVIÓN OFFLINE (Aislado de Red) ] |
+-------------------------------------------------------------+
| [ PESTAÑA: EMISOR (A) ] | [ PESTAÑA: RECEPTOR (B) ] |
+-------------------------------------------------------------+
| |
| +-------------------------------------------------------+ |
| | CARTUCHO DE DEMO: SOS-10K | |
| +-------------------------------------------------------+ |
| |
| [!] COMANDOS SEMÁNTICOS DE EMERGENCIA RÁPIDA: |
| |
| +-------------------------------------------------------+ |
| | [ BOTÓN VERDE ] EVACUACIÓN DE SEGURIDAD (18.0 kHz) | |
| | "Código 5020: Evacuación Failsafe Global" | |
| +-------------------------------------------------------+ |
| | [ BOTÓN AMARILLO ] ADVERTENCIA DE TEMPERATURA (18.5 kHz) | |
| | "Código 2010: Sobrecalentamiento en Gabinete LED B" | |
| +-------------------------------------------------------+ |
| | [ BOTÓN ROJO ] CORTOCIRCUITO CRÍTICO (19.0 kHz) | |
| | "Código 1020: Peligro de Incendio Eléctrico" | |
| +-------------------------------------------------------+ |
| |
| +-------------------------------------------------------+ |
| | MÓDULO DE ESCUCHA PASIVA | |
| | | |
| | [ BOTÓN: INICIAR ESCUCHA EN ESTE TELÉFONO ] | |
| | | |
| | Estado: Esperando señal sónica local... | |
| | +-------------------------------------------------+ | |
| | | ESTADO DE ALERTA: IDLE | | |
| | +-------------------------------------------------+ | |
| +-------------------------------------------------------+ |
+-------------------------------------------------------------+
La transmisión de los 4 bytes en el aire se simula asignando cada código semántico crítico del cartucho de demostración a una frecuencia de portadora de audio ultra-específica.
El emisor debe generar un tono puro (onda senoidal) a la frecuencia seleccionada. Para evitar clics audibles molestos en el altavoz y simular una ráfaga limpia de 150 ms, se debe aplicar una rampa de volumen (envolvente ADSR simplificada):
// Ejemplo de implementación de emisión
function emitirTonoNumChat(frecuencia) {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(frecuencia, audioCtx.currentTime);
// Envolvente de volumen (Previene transitorios audibles y ahorra energía)
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.010); // Ataque
gainNode.gain.setValueAtTime(1, audioCtx.currentTime + 0.140);
gainNode.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.150); // Caída
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.start();
oscillator.stop(audioCtx.currentTime + 0.150);
}
El receptor utiliza el micrófono del dispositivo y calcula en tiempo real una Transformada Rápida de Fourier (FFT) para identificar si la amplitud en los bins de frecuencia específicos supera el umbral de ruido ambiental.
fftSize) = 2048.cartridge-demo.json)Para que la PWA sea autónoma, el siguiente diccionario de correspondencia semántica se incrusta directamente en una constante JavaScript local de la aplicación. Mapea la frecuencia acústica recibida con el identificador semántico binario de 4 bytes y el mensaje traducido al lenguaje humano:
{
"cartridge_metadata": {
"id": "SOS-10K",
"version": "1.0.4",
"jurisdiction": "Global-Emergency",
"total_codes": 3
},
"semantic_mappings": [
{
"frequency_hz": 18000,
"payload_hex": "0x803C139C",
"priority": "CRITICAL_FAILSafe",
"display_color": "#0284c7",
"translations": {
"es": "🚨 ALERTA CIVIL: ¡EVACUACIÓN INMEDIATA DEL SECTOR!",
"en": "🚨 CIVIL ALERT: IMMEDIATE SECTOR EVACUATION REQUIRED!"
}
},
{
"frequency_hz": 18500,
"payload_hex": "0x401407DA",
"priority": "WARNING_HIGH",
"display_color": "#f59e0b",
"translations": {
"es": "⚠️ ADVERTENCIA: SOBRECALENTAMIENTO LED (Brillo reducido al 30%)",
"en": "⚠️ WARNING: LED OVERHEATING (Brightness reduced to 30%)"
}
},
{
"frequency_hz": 19000,
"payload_hex": "0xC01403FC",
"priority": "CRITICAL_DANGER",
"display_color": "#ef4444",
"translations": {
"es": "🔥 PELIGRO: CORTOCUITO DETECTADO (Corte de energía activado)",
"en": "🔥 DANGER: SHORT CIRCUIT DETECTED (Power cutoff engaged)"
}
}
]
}
Para garantizar que la aplicación web funcione en Modo Avión estricto inmediatamente después de que el inversor o los bomberos escaneen el código QR, se debe registrar un service-worker.js que intercepte y guarde en la memoria caché local los recursos críticos del proyecto:
const CACHE_NAME = 'numchat-demo-v1';
const ASSETS = [
'/',
'/index.html',
'/styles.css',
'/app.js',
'/manifest.json',
'/favicon.ico'
];
// Instalar el Service Worker y almacenar recursos en caché
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS))
.then(() => self.skipWaiting())
);
});
// Responder desde la caché cuando esté offline
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Al realizar la demo presencial ante inversores o bomberos, calibra la distancia según el modo elegido:
Diseño técnico registrado y protegido bajo la autoría digital inmutable de NumChat.