Cómo construí mi propio JARVIS en un domingo
Empieza con un video en una pestaña abierta
Sábado a la noche. Estoy pasando repositorios en GitHub buscando algo que me inspire. Me detengo en uno llamado dj-turbo — un control de DJ por gestos con la mano usando MediaPipe. Está bien hecho pero básico. Crossfader controlado con la altura de la mano, play/pause con el puño, efectos con la rotación.
Pienso lo mismo que pienso siempre cuando veo un proyecto así: "el principio es lo interesante, no la implementación concreta".
El principio es este: las manos son un dispositivo de entrada con más resolución que un mouse. Tu mano tiene 21 puntos de referencia que MediaPipe puede seguir a 30 frames por segundo desde una webcam barata. Eso es ancho de banda suficiente para expresar intención. No para reemplazar el teclado cuando escribís, pero sí para reemplazar el mouse cuando estás apuntando, arrastrando o eligiendo.
El salto mental: si funciona para mezclar música, tiene que funcionar para controlar la computadora entera.
Me acuesto con la idea dando vueltas.
Domingo 9am: el fork
Forkéo dj-turbo y le agrego cosas que siempre me faltaron. Doble deck, así podés mezclar dos canciones en vez de una sola. Un crossfader vertical que se controla con la altura de la mano. Visuales reactivas al audio, un espectro FFT que late con la canción. SelfieSegmentation de MediaPipe para que el fondo quede negro y la persona aparezca iluminada con un foco rojo, como si estuvieras en una cabina real. Un grabador de sesión que exporta el mix en MP4.
Le pongo nombre: nexo-dj. Lo publico en GitHub. Son cuatro horas de trabajo.
Y acá es donde pasa la cosa interesante. Mientras lo armaba, me di cuenta de que el 80% del código no era específico de DJ. Era detección de gestos, composición de frame, render de HUD. El DJ era solo una capa delgada encima.
Si saco la capa de DJ y pongo una capa de control de sistema operativo, tengo otra cosa.
Mediodía: nexo-hands
Empiezo un proyecto nuevo en blanco. Le llamo nexo-hands. La idea es clara: JARVIS de Iron Man pero sin la fantasía de sci-fi — solo las capacidades que hoy son reales.
Defino nueve gestos. Puño cerrado para agarrar una ventana. Mano abierta para soltarla. Victoria con dos dedos para navegar. Tres dedos para volumen. Una mano apuntando para llevar el cursor a otra pantalla. Dos manos abiertas sostenidas durante un segundo para activar el modo gestos entero.
Tengo tres monitores — uno grande en el escritorio, otro chico a la derecha, una TV en lo alto. El truco que más me divierte armar es el "throw": agarrás la ventana con el puño, la movés rápido en una dirección, abrís la mano. La ventana sale volando hacia el monitor que estabas apuntando. Como en Minority Report, pero funcionando.
La base técnica es simple porque MediaPipe hace el trabajo pesado. Google lleva años optimizando ese modelo. Corre en la CPU sin despeinarse. Lo que sí tuve que resolver fue la parte de macOS: pyobjc para hablar con la API de Accessibility, CGWindowListCopyWindowInfo para enumerar las ventanas abiertas, NSWorkspace para saber qué app es cada una, CGWarpMouseCursorPosition para teletransportar el cursor.
Son cuatro horas más.
4pm: agregar voz
Los gestos funcionan pero tienen un límite físico. No podés pedirle que abra YouTube gesticulando. No podés dictar un mensaje con la mano. Los gestos son buenos para manipular lo que ya ves en pantalla. Para invocar cosas nuevas necesitás lenguaje.
Meto Whisper local — la versión tiny, corre en CPU — para detectar dos palabras clave: "despierta" enciende el modo voz, "descansa" lo apaga. Whisper tiny no es preciso pero para dos palabras alcanza. Y corre offline, no manda audio a ningún lado hasta que la wake word se activa.
Cuando te escucho decir "despierta", paso a otra cosa. El audio crudo de tu voz se empaqueta en WAV y se manda a Gemini 3.1 Flash Lite por la API REST. Gemini escucha el audio directamente — no lo pre-transcribo — y decide qué herramienta invocar. Tengo doce herramientas definidas: open_url, open_app, type_text, search_google, play_pause, next_track, copy_clipboard, query_web, y algunas más.
"Abre YouTube" → Gemini llama open_url con youtube.com.
"Reproduce el video" → llama play_pause.
"Dime las noticias de IA más importantes de hoy" → llama query_web con la pregunta.
Ese último es el que me divierte. query_web dispara otra llamada a Gemini con Google Search grounding activado. Le da acceso a internet real. Me contesta con noticias de hoy, con fuentes citadas, y la respuesta se lee en voz alta por el TTS de macOS (voz Paulina, español México).
La arquitectura termina siendo: wake word local gratis, comando con audio multimodal a la nube (dos centavos por interacción), respuesta hablada local gratis. Nada más.
7pm: la capa visual
El último bloque es hacer que el sistema se vea como algo, no como un feed de webcam crudo.
SelfieSegmentation otra vez, esta vez en nexo-hands. Separa la silueta de la persona del fondo. Al fondo le aplico un GaussianBlur de kernel 151 más un oscurecido pronunciado — efecto vidrio esmerilado casi opaco. A la persona la dejo nítida. El resultado es que vos aparecés como enfocado en una escena ambient, que es exactamente la estética que buscaba.
Arriba pongo el HUD: una consola lateral izquierda que muestra lo que el sistema está oyendo, pensando y ejecutando paso a paso — como un console.log pero visual. Un indicador circular pulsante que cambia de color según el estado: gris si está dormido, verde si te escucha, ámbar si está procesando con Gemini, rosa si está hablándote. Una leyenda lateral con los gestos disponibles. Subtítulos centrados con lo que estás diciendo, estilo Netflix.
11pm: miro lo que construí
El día empezó viendo un video de un repo en GitHub. Termina con una computadora que responde a gestos en tres pantallas, entiende comandos de voz en español, busca cosas en internet cuando le pregunto, y me lee las respuestas en voz natural.
Lo que me llama la atención no es el sistema en sí — es el camino.
Hace cinco años esto era un proyecto de un doctorado. Tenías que entrenar tu propio modelo de tracking de manos, escribir un parser de audio desde cero, levantar un transcriptor con redes neuronales custom, y todavía te faltaría la capa de razonamiento para entender "reproduce el video". Cada una de esas partes era su propio campo.
Hoy cada pieza está commoditizada. MediaPipe es gratis y lo mantiene Google. Whisper es open source y corre en una laptop. Gemini 3.1 cuesta centavos por llamada y entiende audio y texto en la misma request. macOS trae TTS incorporado hace veinte años. El trabajo mío no fue inventar ninguna de esas piezas — fue conectarlas con cuatro cientos líneas de Python.
Lo que cambió no es la tecnología individual. Lo que cambió es que ensamblar se volvió trivial. El valor se movió de "saber implementar" a "saber qué combinar".
Lo que me queda
Dos repos abiertos:
- github.com/demianolmedo/nexo-dj
- github.com/demianolmedo/nexo-hands
Los dos son MIT, úsenlos, forkeen, mejoren. Yo voy a seguir afinando nexo-hands durante la semana — quiero integrar seguimiento ocular para cuando mirás una ventana específica, y explorar si puedo meter un modo "Minority Report" más completo con arrastre multi-ventana.
Pero el punto del ejercicio no era el producto final. Era probarme que en un domingo, con las APIs que existen hoy, uno puede llegar de "idea bonita en Twitter" a "sistema funcionando en tu escritorio" sin pasar por un doctorado, ni una empresa, ni un presupuesto.
Y si podés llegar vos, imaginá lo que va a llegar cuando esto sea el punto de partida estándar para cada nuevo desarrollador que empiece.
— Demian Olmedo, CEO AgentesNexo
agentesnexo.com
Querés armar tu propia versión? Los dos repos están en github.com/demianolmedo — MIT, forkealos.
