160 lines
8.1 KiB
Markdown
160 lines
8.1 KiB
Markdown
# 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.
|