# primitives_gallery Catalogo visual interactivo de los primitivos UI del registry (`cpp/functions/core` y `cpp/functions/viz`). Un solo ejecutable con sidebar izquierdo + panel derecho que renderiza la demo del primitivo seleccionado con todas sus variantes y un snippet de codigo. ## Rol | Funcion | Como lo cumple | |---|---| | Smoke test visual | Abrir la gallery tras un cambio en tokens / componentes; si algo se ve raro, lo cazas en segundos. | | Documentacion viva | Cada demo muestra el componente trabajando + el snippet exacto. Mas rapido que leer los `.md`. | | Build gate | Esta en el CMake principal (`cpp/CMakeLists.txt`). Si un primitivo rompe API, la gallery no compila => CI rojo. | | Sandbox de prototipos | Datos sinteticos, sin backend; ideal para iterar un primitivo nuevo sin tocar el dashboard. | ## Build & run ```bash # Linux cmake --build cpp/build/linux --target primitives_gallery -j$(nproc) ./cpp/build/linux/apps/primitives_gallery/primitives_gallery # Windows (cross-compile) cmake --build cpp/build/windows --target primitives_gallery -j$(nproc) # binario: cpp/build/windows/apps/primitives_gallery/primitives_gallery.exe ``` No se conecta a `sqlite_api` ni a ningun backend. Datos sinteticos generados in-memory. ## Demos disponibles ### Core | Demo | Primitivo | Que muestra | |---|---|---| | button | `button_cpp_core` | 4 variantes x 3 sizes | | icon_button | `icon_button_cpp_core` | Glyphs comunes con tooltip | | toolbar | `toolbar_cpp_core` | Dos grupos con separador vertical | | modal_dialog | `modal_dialog_cpp_core` | Boton que abre modal con form | | text_input | `text_input_cpp_core` | 3 inputs con placeholder | | select | `select_cpp_core` | Dropdown con y sin `(none)` | | toast + inbox | `toast_cpp_core` (v1.1) | 4 botones que disparan toasts + campana con badge | | tree_view | `tree_view_cpp_core` | Arbol fake de proyectos -> apps | | badge | `badge_cpp_core` | 6 variantes semanticas | | empty_state | `empty_state_cpp_core` | Lista vacia con icono + cta | | page_header | `page_header_cpp_core` | Header con toolbar a la derecha | | dashboard_panel | `dashboard_panel_cpp_core` | Panel con titulo y borde | | kpi_card | `kpi_card_cpp_viz` (v1.2) | Grid 1x4 con sparklines y delta | ### Viz | Demo | Primitivo | Que muestra | |---|---|---| | bar_chart | `bar_chart_cpp_viz` (v1.2) | Labels que caben + labels rotados 45 | | pie_chart | `pie_chart_cpp_viz` (v1.1) | Pie + donut con tooltip por slice | | line_plot | `line_plot_cpp_viz` (v1.1) | Serie sintetica `sin(t) + ruido` | | scatter_plot | `scatter_plot_cpp_viz` (v1.1) | 120 puntos con correlacion | | histogram | `histogram_cpp_viz` (v1.1) | 300 muestras gaussianas | | sparkline | `sparkline_cpp_viz` | Trending up / down / flat | | graph_viewport | `graph_viewport_cpp_viz` | **Ver seccion abajo** | ## Demo `graph_viewport` (en detalle) Pipeline completo de visualizacion de grafos con instanced GPU rendering: - `graph_renderer_cpp_viz` (1 draw call para todos los nodos via `glDrawArraysInstanced`) - `graph_force_layout_cpp_viz` (Barnes-Hut, paso de simulacion por frame) - `graph_spatial_hash_cpp_core` (hit-testing O(1) bajo el cursor) - `graph_viewport_cpp_viz` (widget que orquesta los anteriores con pan/zoom/select) ### Controles | Control | Rango | Efecto | |---|---|---| | `Nodes` | 100 – 20 000 | Numero de nodos a generar | | `Clusters` | 2 – 16 | Numero de comunidades (cada una con su color) | | `Repulsion` | 100 – 20 000 | Fuerza repulsiva entre todos los nodos. Mas alto => grafo mas extendido y energia mayor. | | `Attraction` | 0.001 – 0.5 | Constante del muelle de las aristas. Mas alto => clusters mas compactos. | | `Gravity` | 0.0 – 0.05 | Tiron hacia (0,0). Util para evitar drift cuando subes mucho la repulsion. | | `Regenerate` | boton | Regenera el grafo con los valores actuales de Nodes/Clusters. | | `Pause / Resume layout` | boton | Para o reanuda la simulacion force-directed. | | `Fit view` | boton | Encuadra la camara al bounding box del grafo con 10% de padding. | Los tres sliders de fuerzas se leen cada frame y se inyectan en `ForceLayoutConfig`, asi que cambiar un valor durante el layout en marcha re-calibra el sistema al instante. ### Stats line (sin vibracion) Una sola linea fija — sin secciones condicionales que cambien la altura del panel: ``` nodes=N edges=E energy=X fps=F | hover=#id cN sel=#id ``` `hover` y `sel` muestran `-` cuando no hay nada seleccionado para mantener el ancho/alto estable; antes una fila condicional desplazaba el viewport en cada hover. ### Interaccion con el viewport | Gesto | Accion | |---|---| | Drag con boton izquierdo en zona vacia | Pan de camara | | Wheel | Zoom (limites 0.01x – 50x) | | Drag sobre nodo | Mueve el nodo (lo `pin`ea durante el drag) | | Click sobre nodo | Selecciona (`s_state.selected_node`) | | Hover sobre nodo | Resaltado + `s_state.hovered_node` poblado | ### Datos sinteticos `generate_synthetic_graph(N, K)` reparte N nodos en K clusters dispuestos en circulo, con ~3 aristas intra-cluster por nodo y un 5% adicional de aristas inter-cluster. Paleta de 8 colores ABGR. Posiciones iniciales con dispersion gaussiana de 80 px alrededor del centroide del cluster — el force layout las reordena en pocos frames. ### Performance esperada | Nodes | FPS objetivo (RTX 30xx, viewport 800x460) | Notas | |---|---|---| | 1 000 | 60 (vsync) | Caso comun; layout converge < 1 s | | 5 000 | 60 | Pipeline al limite del CPU para Barnes-Hut | | 20 000 | 30 – 50 | El cuello pasa a ser el layout (CPU); GPU render sigue holgado | Si necesitas mas, fija los nodos (`pinned = true` o `Pause layout`) y veras 60 fps estables — el bottleneck es la simulacion, no el render. ## Anadir un demo nuevo 1. Anadir el prototipo en `demos.h` dentro de `namespace gallery`: ```cpp void demo_my_thing(); ``` 2. Implementar el cuerpo en `demos_core.cpp` o `demos_viz.cpp` (o un fichero nuevo si la demo es grande, p.ej. `demos_graph.cpp`). 3. Registrar la entrada en el array `k_demos[]` de `main.cpp`: ```cpp {"my_thing", "my_thing", "Core" /* o "Viz" */, &gallery::demo_my_thing}, ``` 4. Si la demo necesita `.cpp` adicionales del registry, anadirlos a `CMakeLists.txt` de la gallery. 5. Recompilar. ## Estructura ``` cpp/apps/primitives_gallery/ CMakeLists.txt # target primitives_gallery README.md # este fichero main.cpp # sidebar + router demo.{h,cpp} # helpers (demo_header, section, code_block, ...) demos.h # prototipos void demo_xxx() demos_core.cpp # demos del dominio core demos_viz.cpp # demos del dominio viz (charts simples) demos_graph.cpp # demo de graph_viewport (mas pesada, fichero aparte) ``` ## Convenciones para los demos - **Sin estado real**: usar arrays sinteticos (`float fake[] = {...}`) o generadores deterministas con seed fijo. Datos reproducibles. - **Sin red**: nunca llamar a `sqlite_api`, HTTP, filesystem. La gallery debe arrancar offline en cualquier maquina. - **Snippets honestos**: el `code_block(...)` debe mostrar el codigo que produce esa demo, no pseudocodigo. - **Variantes en grids**: si un primitivo tiene N variantes x M tamanos, mostrarlos todos en un `BeginTable` para comparacion lado-a-lado. - **Estado static**: si la demo es interactiva (sliders, modal, etc.), guardar el estado en `static` locales — la gallery no destruye demos al cambiar de seccion, asi que el estado persiste hasta cerrar la app. ## Iconos en los demos A partir de la sesion 2026-04-25 los demos usan los macros `TI_*` de `cpp/functions/core/icons_tabler.h` (Tabler v3.41.1, 5093 glyphs). La fuente la carga automaticamente `fn::run_app` via `icon_font_cpp_core`, y `add_imgui_app` copia `tabler-icons.ttf` junto al ejecutable post-build (no hay paso manual). `demo_icon_button` y `demo_toolbar` (en `demos_core.cpp`) son la referencia visual: muestran el patron `button(TI_PLUS " New", V::Primary)` y la fila de iconos sueltos. Ver `cpp/DESIGN_SYSTEM.md` seccion 11 para la regla. Si añades un demo nuevo y necesitas glyphs, **no metas `\x..` UTF-8 inline** — busca el icono en `icons_tabler.h` (o en https://tabler.io/icons) y usa el `TI_*` correspondiente.