Contexto

Xnapper es una herramienta comercial de capturas de pantalla que se expandió hacia la edición de imagen y video. Como Desarrollador de Software del equipo, fui responsable de features en la interfaz, el estado de la aplicación, el procesamiento, la persistencia y las integraciones con servicios — no de una sola capa del stack.

La dificultad técnica surgió al pasar de la edición estática de capturas a flujos de video cuadro a cuadro que debían mantenerse confiables y mantenibles en distintos entornos de ejecución, sin sacrificar performance.

Mi alcance de punta a punta

Frontend y experiencia de producto

Construí interfaces de edición con React y Next.js: timeline, manipulación de clips, reproducción y controles de exportación.

Estado y lógica de aplicación

Modelé el estado del editor, el historial de undo/redo y la persistencia de sesiones y presets, conectando la interfaz con los distintos flujos del producto.

Procesamiento

Implementé el procesamiento de video con Node.js, FFmpeg y WebAssembly, coordinando archivos, reproducción, progreso y generación de resultados.

Backend y datos

Diseñé y publiqué un servicio serverless de licenciamiento que aplicaba reglas comerciales por dispositivo y persistía el estado de las activaciones en Redis.

UI en React / Next.js
Estado y lógica del editor
Procesamiento en Node.js (FFmpeg / WASM)
Servicio backend serverless
Persistencia en Upstash Redis

El producto necesitaba dejar atrás la edición estática de capturas y soportar flujos de video confiables sin sacrificar performance, mantenibilidad ni consistencia entre entornos.

Lo que construí

La aplicación creada con Electron utiliza la aplicación web de Xnapper

Pipeline de edición de video

Construí esta capacidad de punta a punta: desde las interacciones de timeline y el modelado del estado hasta la extracción de frames, el procesamiento y la exportación final.

  • Diseñé la interfaz y las interacciones de timeline, clips y playhead.
  • Modelé el estado de edición, la normalización de clips y el historial de undo/redo.
  • Construí la reproducción y la búsqueda precisa cuadro a cuadro.
  • Implementé el procesamiento y la exportación con FFmpeg/WASM.
  • Integré progreso, cancelación, manejo de errores y generación del archivo final.

Autenticación e integraciones

  • Implementé el flujo de autenticación con Google OAuth para la web y la aplicación de escritorio.
  • Reforcé el manejo y la renovación de sesión para mantener autenticados los flujos del producto.

Servicio backend de licenciamiento

Diseñé y publiqué un backend serverless para validar licencias comerciales y controlar la cantidad de dispositivos asociados a cada usuario.

  • Construí el endpoint de validación con Node.js y Express, desplegado como función serverless.
  • Modelé licencias y dispositivos activos sobre Upstash Redis.
  • Apliqué reglas de límite de asientos por dispositivo.
  • Implementé activación idempotente para evitar duplicar registros en validaciones repetidas.
  • Manejé la baja lógica (soft-delete) de dispositivos sin perder el historial de activaciones.

Estado y arquitectura del producto

  • Abstracción de Export Strategy
  • Historial de undo/redo basado en el patrón Memento
  • Persistencia de sesión y presets
  • Consistencia de comportamiento entre runtimes

Confiabilidad y seguridad

  • Manejo más seguro de archivos y rutas
  • Reducción de la superficie de ataque del servidor local
  • Eliminación de integraciones de procesos inseguras
  • Tests automatizados para flujos críticos

Decisiones

Extracción de frames basada en demuxer

La búsqueda nativa de video no era confiable en material con frame rate variable — podía terminar en el cuadro incorrecto, rompiendo la edición cuadro a cuadro.

Extraje los cuadros a través de un demuxer en lugar de depender de la búsqueda nativa, dándole al editor una fuente consistente y precisa sin importar la codificación original del clip.

Estrategias de exportación

Soportar múltiples destinos de exportación estaba esparciendo lógica condicional por todo el código, haciendo cada vez más riesgoso agregar una nueva opción de exportación.

Introduje una interfaz compartida de export strategy para que cada destino implemente el mismo contrato, concentrando la lógica de ramificación en un solo lugar en vez de condicionales dispersos.

Modelo idempotente de activación

El cliente podía validar la misma licencia repetidamente, y un dispositivo ya activo no debía duplicar su registro ni ocupar más de un lugar disponible.

Diseñé la activación como una operación idempotente: si el dispositivo ya estaba activo, el servicio devolvía éxito sin duplicar el registro. Las bajas se modelaron con soft-delete para conservar el historial sin consumir un lugar disponible.

Resultado

  • Expandí el producto desde flujos enfocados en capturas hacia la edición de video.
  • Entregué el trabajo a través de múltiples releases de producción.
  • Mejoré la mantenibilidad de los flujos de exportación y persistencia.
  • Reduje riesgos importantes de seguridad y confiabilidad.
  • Di soporte a un producto usado por aproximadamente 20.000 usuarios.

Stack

  • TypeScript
  • React
  • Next.js
  • Node.js
  • Electron
  • FFmpeg / WebAssembly
  • WebGL
  • Zustand / Jotai
  • Redis / Upstash
  • Jest / Vitest
Ver mi currículumHablemosVolver al portfolio