Índice, recorrido por capas y glosario. Si es tu primera vez aquí, lee esta página y luego el documento de la capa o función que te interese.
Telemetry Studio es una app de escritorio (Electron 34 + React 19 + TypeScript) para analizar telemetría de robots de competición con vídeo pregrabado sincronizado. Funciona 100 % offline y portable. Captura por Serial o carga sesiones guardadas, dibuja la telemetría con widgets (uPlot/Canvas 2D), sincroniza todo con el vídeo por timestamp, permite comparar dos sesiones y exportar vídeo MP4 con los gráficos superpuestos.
| Documento | Contenido | Cuándo leerlo |
|---|---|---|
| 00 — Visión general | Casos de uso, flujos, restricciones | Para entender el producto |
| 01 — Arquitectura | Diagramas y flujos main/renderer/IPC | Antes de tocar el código |
| 02 — Stack tecnológico | Decisiones (Electron, uPlot, Zustand…) | Para dudas de por qué cada tecnología |
| 03 — Estructura de carpetas | Árbol de ficheros y reglas de dependencias | Para encontrar dónde vive algo |
| 04 — Modelo de datos | Tipos TS, EventMap, modelos de export/sesión |
Al trabajar con datos |
| 05 — Sistema de plugins | Parsers y widgets | Para añadir un parser/widget |
| 06 — Sincronización vídeo | VideoSynchronizer, anchor/drift |
Para entender el sync |
| 07 — Motor de datos | EventBus, TelemetryStore, ComparisonManager, búsqueda/LTTB | Al trabajar con el core |
| 08 — Sistema de widgets | Los 4 widgets, rejilla, auto-layout | Para tocar widgets |
| 09 — Exportación de vídeo | Asistente de 2 pasos, composición, FFmpeg | Para tocar la exportación |
| 10 — Layout Manager | Persistencia de layouts y edición por arrastre | Para tocar layouts |
| 11 — Empaquetado | electron-builder, CI/CD, sidecar FFmpeg | Para publicar builds |
| 12 — Limitaciones | Known issues y workarounds | Antes de reportar/arreglar |
| 13 — PoCs | Pruebas de concepto obligatorias | Para reproducir validaciones |
| 14 — Formato de sesión | Especificación de session.json |
Para leer/escribir sesiones |
| ROADMAP | Fases y timeline | Para contexto histórico |
| AGENTS | Guía para agentes/colaboradores | Al contribuir |
La regla de oro: el renderer nunca importa de main/; toda comunicación pasa por
IPC. shared/ no depende de nada; main/ no depende del renderer.
main/ Node.js: ciclo de vida, serialport, ffprobe/transcode, FFmpeg, I/O de ficheros
preload/ contextBridge → window.api (tipado en renderer/src/global.d.ts)
renderer/ UI React + stores Zustand; orquesta todo
core/ motor de datos puro-lógico (EventBus, TelemetryStore, VideoSynchronizer…)
parsers/ entrada de datos (Serial, JSON)
widgets/ visualización (TimeSeriesChart, DigitalBitmask, Minimap2D, StateTimeline)
services/ orquestación (layout, sesión, exportación)
shared/ utilidades puras compartidas (rejilla, composición, args FFmpeg)
Dependencias: shared ← core ← parsers/widgets ← services ← renderer;
main depende solo de shared. Detalle en 03.
- Serial + Vídeo: cargar vídeo → conectar Serial → streaming → auto-layout → «Alinear aquí» (anchor) → analizar → guardar sesión.
- Sesión guardada: abrir
session.json→ se restaura telemetría, sync, layout y board de exportación → analizar. - Comparación: sesión A + sesión B (widgets idénticos y en el mismo orden) →
SplitViewen paralelo con reproducción/cursor/zoom sincronizados. - Exportación: requiere telemetría → asistente de 2 pasos (board + salida) →
ExportStagecompone frames → raw RGBA → FFmpeg → MP4 H.264.
| Término | Significado |
|---|---|
| TelemetryFrame | Muestra individual: { timestamp_ms, data }. |
| TelemetryDataset | Conjunto de frames + schema + startTime_ms/endTime_ms/duration_ms. |
| DataSource | Origen del dataset: session o serial. |
| EventBus | Pub/Sub tipado por EventMap; eventos de alto nivel (sync:frame, data:*, comparison:*…). |
| FrameBus | Bus por panel que entrega el frame sincronizado a los widgets; redibujado imperativo sin re-render React. |
| TelemetryStore | Almacén de frames en memoria: dataset primario + comparación. Búsqueda binaria por timestamp. |
| VideoSynchronizer | Motor que mapea el tiempo de vídeo a timestamp de telemetría (mapTime) con anchor y drift; su inversa es unmapTime. |
| Anchor | Punto de alineación { video_ms, telemetry_ms }; «Alinear aquí» fija el frame actual como t=0 de telemetría. |
| Drift | Desfase manual (driftOffset_ms, hoy siempre 0 en la app); se miden averageDrift/maxDrift. |
| viewTimestamp_ms | Timestamp de telemetría mapeado desde el frame de vídeo (lo consumen los widgets). |
| LTTB | Largest-Triangle-Three-Buckets: downsample que conserva picos; se aplica por encima de maxPoints (2000). |
| ComparisonManager | Valida widgets idénticos (posición a posición) y carga el dataset de comparación. |
| Layout | Disposición del dashboard (widgets en rejilla de 12 columnas + paneles + board de export). |
| Board (export) | Composición del vídeo de exportación: ítems widget/video/section en rejilla. |
| Supersampling | Renderizar los widgets a 2× y reducirlos al componer (mejor antialiasing, más lento). |
| CRF / Preset | Parámetros de calidad/velocidad de libx264. |
| Sidecar | Binario FFmpeg empaquetado junto a la app (o del PATH como fallback). |
| SessionFile | session.json compacto: video + sync + telemetry + layout + export?. Ver 14. |
| PoC | Prueba de concepto en pocs/ que valida una parte del stack. |
npm install
npm run dev # Electron + HMR
npm run build # Build de producción
npm run test # Vitest
npm run verify # lint + typecheck + tests + build + smoke + e2e (gate completo)Otros: npm run smoke, npm run e2e (12 pruebas), npm run e2e:perf (standalone),
npm run screenshots, npm run lint, npm run typecheck, npm run poc:1…poc:4.
Requiere Node 20+ (probado con Node 20) y FFmpeg como sidecar para exportar/transcodificar.
- Layouts (solo los guardados por el usuario):
app.getPath('userData')/layouts/. - Ajustes (p. ej. config Serial):
userData/settings.json. - Sesiones: carpeta con
session.json+ copia del vídeo donde el usuario las guarde.