Extiende el modelo agnostico de graph_types.h para soportar shapes/iconos/ filtros/labels/streaming sin acoplar a backend. Migra el unico consumer (demos_graph) en el mismo cambio. - GraphNode v2: type_id + shape_override/color_override/size_override + flags (NF_PINNED/VISIBLE/SELECTED/HOVERED) + label_idx + user_data. - GraphEdge v2: type_id + style_override + flags (EF_DIRECTED/VISIBLE). - EntityType / RelationType: tablas en GraphData (types, rel_types). - Helpers de resolucion (resolve_node_color/shape/size, resolve_edge_*) y constructores ergonomicos (graph_node, graph_edge, entity_type, relation_type) — sentinel-based para herencia automatica del tipo. - graph_renderer v1.4: lee NF_VISIBLE / EF_VISIBLE, resuelve apariencia via override → EntityType → fallback indexado por type_id. Skipea aristas con endpoints invisibles. Shapes siguen pintandose como circulo (0049f cableara el dispatch real). - graph_force_layout v1.2: pinned ahora vive en flags & NF_PINNED. - graph_viewport v1.1: hover/seleccion publican NF_HOVERED/SELECTED en el grafo (clear-then-set). Drag usa NF_PINNED. Tooltip muestra Type/ user_data en lugar de community/value/label. - demos_graph: 8 EntityType (paleta antigua) + 1 RelationType. type_id por cluster. user_data = indice numerico del nodo. Apariencia visual identica al pre-cambio. - test_graph_types.cpp: 12 casos cubriendo helpers, defaults, bitmask manipulation y resoluciones override-vs-EntityType. test_graph_edge_ static actualizado al nuevo modelo (ya no tiene .color directo). - 4 .md de tipos nuevos (graph_node, graph_edge, entity_type, relation_type) + GraphData v2.0 actualizado. Tests: 31/31 ctest verdes (incluye test_visual golden). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
# 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 viaglDrawArraysInstanced)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 pinea 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
- Anadir el prototipo en
demos.hdentro denamespace gallery:void demo_my_thing(); - Implementar el cuerpo en
demos_core.cppodemos_viz.cpp(o un fichero nuevo si la demo es grande, p.ej.demos_graph.cpp). - Registrar la entrada en el array
k_demos[]demain.cpp:{"my_thing", "my_thing", "Core" /* o "Viz" */, &gallery::demo_my_thing}, - Si la demo necesita
.cppadicionales del registry, anadirlos aCMakeLists.txtde la gallery. - 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
BeginTablepara comparacion lado-a-lado. - Estado static: si la demo es interactiva (sliders, modal, etc.), guardar el estado en
staticlocales — 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.