Files
fn_registry/docs/diary/2026-04-25.md
T

353 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-04-25
## 15:32 — shaders_lab fase 7 (UX node editor + correcciones DAG)
Pulido de la edición visual del DAG y corrección de fugas en el render. Coexiste con la Fase 6 (menubar View + Layouts) que añadió otro agente en paralelo.
### Hecho — UX nodos
- Hecho: nodos más grandes para conectar más rápido. `PIN_RADIUS` 9 → 14, `CABLE_THICK` 2.5 → 3.5, `CONTROL_WIDTH` 150 → 220, `COL_GAP` 8 → 14, `NodePadding` vertical 8 → 12, espaciado inicial entre nodos 220 → 320.
- Hecho: bug fix `solid` "sin nombre ni parámetro". El control `Color` se renderizaba con `ImGuiColorEditFlags_NoLabel`. Ahora `TextUnformatted(label) + SameLine` antes del swatch (aplica a todos los Color, no solo a `solid`).
### Hecho — Drop comportamiento (paleta + nodos del canvas)
- Hecho: drop sobre nodo del **mismo `DagKind`** (no Output) → replace. Conserva `id`, `editor_uid`, posición, `source_ids[]`, `preview_open`. Limpia slots de input que sobran.
- Hecho: drop sobre cable → splice. `new.source_ids[0] = src.id`, `dst.source_ids[slot] = new.id`. Hit-test = distancia punto-segmento entre cursor y línea (`src.right_mid → dst.left_at_slot_k`). Threshold 18 px canvas-space.
- Hecho: arrastrar **nodo Op/Blend ya colocado** sobre cable también splica. Tracking via `s_drag_existing_uid` (set en `IsMouseClicked(0)` con node hovered y sin pin hovered). Al soltar, refs hacia el nodo movido se limpian antes del rewire (queda exclusivamente en la nueva posición).
- Hecho: prioridad cable-hit > node-hit > add-vacío.
### Hecho — Splice highlight (preview visual)
- Hecho: cable candidato se pinta `SPLICE_COLOR (1.00, 0.82, 0.18, 1)` + `CABLE_THICK + 2` en `ed::Link()`.
- Hecho: además se redibuja como bezier dorado en `ImGui::GetForegroundDrawList()` (canvas → screen via `ed::CanvasToScreen`) para no depender del compositing interno de imgui-node-editor.
- Hecho: detección sin gates. La versión inicial gateaba con `IsMouseDown` + `window_hovered` y silenciaba el highlight. Basta payload `DAG_NODE_TYPE` (paleta) o `s_drag_existing_uid` (nodo del canvas).
### Hecho — Correctness DAG
- Hecho: **strict output** en `compile_dag_to_glsl`. Eliminado el fallback `last_valid_out` que filtraba el output del último nodo cuando `Output` no tenía source o no existía. Ahora regla: solo se emite lo conectado al `Output`; en cualquier otro caso `seed()` (gris oscuro). El `resolve()` interno de inputs también devuelve `vec4(0,0,0,1)` para slots vacíos (antes caía a `last_valid_out`).
- Hecho: `dag_uniforms_apply` resetea `u_preview_target = -1` al final, para que la rama de preview quede desactivada en el render principal del Canvas DAG.
- Hecho: nuevo `compile_dag_to_glsl_baked(pipeline)` en `dag_compile.{h,cpp}`. Sustituye `uniform vec4 u_params[64]` por `const vec4 u_params[N] = vec4[N](...)` con valores actuales empaquetados, y `uniform int u_preview_target` por `const int u_preview_target = -1`. El panel `Generated GLSL` muestra esta variante: pegarla en el editor `Code` reproduce el render del DAG en el momento del copy, sin depender de uniforms externos. Edits posteriores al DAG no afectan al Code.
- Hecho: `Canvas Code` ya NO recibe `dag_uniforms_apply` (versión anterior lo acoplaba). Es totalmente independiente del DAG.
### Hecho — Tests + builds
- Hecho: `dag_compile` 6/6 → **8/8** (test 4b strict output sin Output, test 7 baked variant).
- Hecho: `dag_catalog` 8/8 (19 nodos), `code_to_generator` 7/7, `uniform_parser` 6/6, `shaderlab_db` 7/7. Total **35 asserts** en gfx tras la fase.
- Hecho: build linux + windows OK. `./fn index` pasa a 899 funciones.
- Hecho: sync de `shaders_lab.exe` a `apps/shaders_lab/` (in-repo) y a `/mnt/c/Users/lucas/Desktop/`. MD5 final `33fa56c60584adc074679d39f307e19e`.
### Hecho — Operativo
- Hecho: regla nueva en memoria persistente — `feedback_no_adminlocal.md`. **Nunca** copiar binarios Windows a `/mnt/c/Users/AdminLocal/`. Solo `/mnt/c/Users/lucas/Desktop/`. Borrado el `shaders_lab.exe` que quedaba allí.
- Hecho: `cpp/CMakeLists.txt` centraliza `sqlite3_vendored` (top-level) para que `shaders_lab` y `registry_dashboard` lo compartan sin colisión de target. Ambos CMakeLists internos usan `find_package(SQLite3 QUIET)` + `if (NOT SQLite3_FOUND AND NOT TARGET sqlite3_vendored)`.
### Pendiente
- Pendiente: panel `View` con listado / borrado de generators custom desde la UI (hoy solo via DB directa).
- Pendiente: botón `Push to registry` que extrae un generator custom a `cpp/functions/gfx/<name>.{cpp,md}` con tag `shaders_lab` y dispara `fn index`.
- Pendiente: persistencia de pipelines con nombre.
- Pendiente: `Save as Op` (1 input `a`) y `Save as Blend` (2 inputs).
### Referencias
- App: `apps/shaders_lab/app.md` — Fase 7 documentada en `## Estado actual`.
- Funciones tocadas: `dag_node_editor_cpp_gfx`, `dag_compile_cpp_gfx`, `dag_uniforms_cpp_gfx`, `dag_catalog_cpp_gfx`. Notas appended en cada `.md`.
- Funciones nuevas (Fase 5, ya documentadas): `code_to_generator_cpp_gfx`, `shaderlab_db_cpp_gfx`.
- Memoria: `feedback_no_adminlocal.md`.
## 15:33 — Projects view + mutaciones desde el dashboard, gallery de primitivos
Sesion larga repartida en tres fases (plan acordado al principio): primitivos UI nuevos en `cpp/functions/core/`, endpoints de mutacion en `sqlite_api`, e integracion en el dashboard. Cierra con la primera capa del plan de tests (gallery interactiva).
### Hecho — Fase A (9 primitivos UI nuevos)
Todos con `.cpp + .h + .md`, compilando Linux + MinGW posix:
- `button_cpp_core`, `icon_button_cpp_core`, `toolbar_cpp_core` — interaccion basica con tokens.
- `modal_dialog_cpp_core`, `text_input_cpp_core`, `select_cpp_core` — formularios.
- `toast_cpp_core` v1.1 — push thread-safe + render por frame + `toast_inbox_button` con badge no-leidos + popover con historial 50 entradas.
- `process_runner_cpp_core``std::thread` + `std::atomic<int> state` + widget `runner_status` con spinner.
- `tree_view_cpp_core` — low-level (`tree_leaf` / `tree_branch_begin/end` / `tree_node_clicked`); el caller gestiona la seleccion.
**Toolchain MinGW**: switch de `win32` a `posix` (`x86_64-w64-mingw32-g++-posix`) para que `std::mutex/std::thread` compilen. Linker: `-static-libgcc -static-libstdc++ -static -lwinpthread`. Sin esto, toast/process_runner no compilan en Windows. Configurado en `cpp/toolchains/mingw-w64.cmake`.
### Hecho — Fase B (sqlite_api v0.2)
Split de handlers en 3 ficheros: `handlers.go` (read-only previo), `handlers_projects.go` (nuevo), `handlers_mutations.go` (nuevo).
- `GET /api/projects` — proyectos con conteos `apps_count/analyses_count/vaults_count` (subqueries) + bloque `orphans`.
- `GET /api/projects/{id}` — detalle apps/analyses/vaults; `id="orphans"` para huerfanas. Helper `scanAll(ctx, db, query, arg)`.
- `POST /api/reindex``exec.CommandContext` de `{registryRoot}/fn index` con timeout 60 s.
- `POST /api/add/app` — body `{name, lang, domain, project, description}` → crea dir + `app.md` minimo + reindex.
- `POST /api/add/analysis` — invoca pipeline `init_jupyter_analysis` via `fn run`.
- `POST /api/add/vault` — solo dentro de proyecto. Crea dir/symlink en `projects/{p}/vaults/` + entry append en `vault.yaml`.
`Server` gana campo `registryRoot string`. `NewServer(pool, root)`. Tests adaptados con `sed -i 's/NewServer(pool)/NewServer(pool, "")/g'`. Reiniciado: `systemctl --user restart sqlite_api`. Smoke OK.
### Hecho — Fase C (dashboard integration)
- **Actions bar** en page header (`fn_ui::toolbar`): `Reindex` (Primary) → `process_runner` con `http_post_reindex`; `+ Add` → modal; `Reload`; `toast_inbox_button("##inbox")`.
- **Modal Add** con kind selector (App/Analysis/Vault), `select` de proyecto, `text_input` Name + Description, campos especificos por kind. Submit dispara endpoint con `process_runner` + toast + reload.
- **Tab Projects** (`tree_view` izquierda + tabs derecha): proyectos + entrada "(orphans)"; click → `load_project_detail_http`.
`RegistryData` gana `projects[]`, `orphan_apps`, `orphan_analyses`, `orphan_vaults`. Tipos nuevos `ProjectRow`, `VaultRow`, `ProjectDetail`. `data_http.cpp` gana `load_projects_http`, `load_project_detail_http`, `http_post_{reindex,add_app,add_analysis,add_vault}`. `AnalysisRow` gana `lang` (query SQL pasa de 4 cols a 5). `views_set_api_url(url)` invocado desde main.
### Bug fix — vibracion al redimensionar
Tres causas combinadas:
- `fullscreen_window` v0.2: `NoScrollbar | NoScrollWithMouse` para evitar scrollbar fugaz cuando el contenido excede la ventana por 1-2 px (reflow del ancho ~14 px).
- `views.cpp::draw_dashboard`: altura de charts pasa de `GetContentRegionAvail().y * 0.35` a constante 260 px. La proporcion relativa propagaba el resize a todos los plots.
- `kpi_card` v1.2: 78 px fijo + scale 1.4 + padding sm + `NoScrollbar`. Antes `AutoResizeY` × 8 cards × cada frame era el lag.
### Bug fix — Reindex POST con timeout 5 ms en Windows
`http_client.cpp::request()` pasaba `struct timeval` (8 bytes en x86_64) a `setsockopt(SO_RCVTIMEO)` en Windows, que MSDN especifica como `DWORD` ms. Resultado: 5 ms efectivos en lugar de 5 s. Critico en POST desde threads de background. Fix: rama `_WIN32` con `DWORD timeout_ms = timeout_sec * 1000`. Tambien `wsa_init` envuelto en `std::call_once` para evitar race entre main thread + runners.
### Bug fix — toast vacio + popup en otra pantalla
- `post_json` ahora siempre escribe en `out_body`: extrae `output` del JSON en exito; sintetiza `"connect() failed to host:port (err=N)"` con codigo Winsock real en error de conexion. Em dash `—` (U+2014) sustituido por `:` ASCII (la fuente default no tenia el codepoint y rendia como `?`).
- `toast_inbox_button` antes usaba `btn_pos.x - 332` que podia caer fuera del `WorkRect`; con `viewports = true` ImGui lo enviaba a otra ventana del OS. Fix: clamp al `WorkRect`, `ImGuiCond_Appearing` (no `Always`), `SetNextWindowViewport(vp->ID)`.
### Hecho — Gallery + plan de tests
Implementada Capa 1 del plan de tests (Gallery + doctest + TestEngine + snapshot PNG):
- **`cpp/apps/primitives_gallery/`** — app dev con sidebar de 19 primitivos + panel con demo + snippet por cada uno. Linkea todos los `core/*.cpp` y `viz/*.cpp` relevantes; al estar en `cpp/CMakeLists.txt` actua como build gate. 3 ficheros de demos: `demos_core.cpp` (13 primitivos), `demos_viz.cpp` (6 charts), `demos_graph.cpp` (graph_viewport, fichero aparte).
- **Demo `graph_viewport`** con sliders `Nodes` (10020 000), `Clusters` (216), `Repulsion` (10020 000), `Attraction` (0.0010.5), `Gravity` (0.00.05), aplicados en vivo a `ForceLayoutConfig`. Stats en una sola linea fija (`hover` y `sel` siempre presentes con `-`, sin filas condicionales que vibren).
- **`README.md`** propio en `cpp/apps/primitives_gallery/` (primer .md en `cpp/apps/*/`; `chart_demo` y `shaders_lab` no tienen).
- `gl_loader_cpp_gfx` v1.1: ampliado con 11 funciones (`glBufferData`, `glDrawArraysInstanced`, `glEnableVertexAttribArray`, `glVertexAttribDivisor`, `glVertexAttribPointer`, `glBindRenderbuffer`, `glDeleteRenderbuffers`, `glFramebufferRenderbuffer`, `glGenRenderbuffers`, `glRenderbufferStorage`, `glFramebufferTexture`) — necesarias para que `graph_renderer` compile en cross-compile MinGW.
- `graph_renderer_cpp_viz` v1.1: cambia raw `<GL/glext.h>` por `gfx/gl_loader.h`. Sin cambios funcionales (Linux bit-equivalente). Cualquier app que use `graph_renderer` debe linkear `gl_loader.cpp` y llamar `fn::gfx::gl_loader_init()` una vez tras crear el contexto GL.
### Investigacion paralela
Pregunta del usuario: motor de grafos eficiente en C++ con miles de circulos compatible con ImGui. Recomendacion: hasta 50 k nodos el stack del registry (`graph_renderer` instanced + `graph_force_layout` Barnes-Hut + `graph_spatial_hash` + `graph_viewport`) es la opcion correcta. `imgui-node-editor` (vendoreado) NO es para visualizacion masiva sino para edicion de DAGs (caso del shaderlab); ImPlot scatter es alternativa rapida si no necesitas aristas; OGDF si Barnes-Hut se queda corto. La gallery sirve como benchmark rapido para validar rendimiento real.
### Pendiente
- Vendora `doctest` (single-header, MIT) + 6 tests de logica + `ctest` (Capa 2 del plan): `label_stride` (bar_chart), `slice_at` (pie_chart), `process_runner` transitions, `toast` queue, `tokens` sanity, `parse_url` (http_client).
- Exponer `label_stride` y `slice_at` fuera de `namespace { ... }` para que sean testables.
- `loginctl enable-linger lucas` para que `sqlite_api.service` (user systemd) sobreviva al logout (decision pendiente).
- Filtros interactivos en sidebar (filtrar tablas Apps/Functions/Types por proyecto).
- Permisos/auth en mutaciones de `sqlite_api` si se considera deploy a VPS.
### Referencias
- `cpp/functions/gfx/gl_loader.md` v1.1 (tabla de cobertura).
- `cpp/functions/viz/graph_renderer.md` v1.1.
- `cpp/functions/core/toast.md` v1.1.
- `projects/fn_monitoring/project.md` — seccion Estado actual con Fase projects view, bug fixes, gallery sibling.
- `projects/fn_monitoring/apps/sqlite_api/app.md` — endpoints `[v0.2]` + Estado actual.
- `projects/fn_monitoring/apps/registry_dashboard/app.md` — Fase actions bar + bug fixes + toolchain MinGW.
- `cpp/apps/primitives_gallery/README.md` — nuevo.
- Commits en sesiones previas (mismo dia): `3f622561` (cpp/viz static-plot + tooltips), `b828fd6a` (kpi v1.2 + bar v1.1), `d6bdab8` en `dataforge/registry_dashboard`. Cambios de esta sesion en working tree, sin commit todavia.
- Reindex final: 899 funciones, 153 types, 13 apps, 2 analysis, 3 projects, 1 vaults, 1293 unit_tests.
## 15:51 — cpp icons via Tabler (TI_* macros, atlas auto-cargado)
Glyphs en apps C++ no renderizaban (cuadritos vacios) porque ImGui usa ProggyClean default sin codepoints simbolicos. Integrado set Tabler v3.41.1 (espejo del frontend `@tabler/icons-react`).
- Hecho: vendoreado `cpp/vendor/tabler-icons/tabler-icons.ttf` (2.7 MB, MIT) + LICENSE + README + `gen_header.py` para regenerar.
- Hecho: generado `cpp/functions/core/icons_tabler.h` con 5093 macros `TI_*` (TI_PLUS, TI_TRASH, TI_REFRESH, TI_DEVICE_FLOPPY, TI_SETTINGS, ...) en formato `#define TI_NAME "\xee\xac\x8b"`.
- Hecho: nueva funcion del registry `icon_font_cpp_core` (impure, error_go_core) con `fn_ui::load_default_fonts(text_px=15, icon_px=14)` — carga texto default + mergea Tabler en el mismo `ImFont` con `MergeMode + GlyphMinAdvanceX = icon_px + GlyphOffset.y = 1` (range U+E000..U+FCFF).
- Hecho: hook en `cpp/framework/app_base.cpp` — llama `fn_ui::load_default_fonts()` justo despues de `ImGui::CreateContext()`. Cualquier app que use `fn::run_app` obtiene los iconos sin tocar nada.
- Hecho: `cpp/CMakeLists.txt` — capturado `FN_CPP_ROOT_DIR` a nivel root, define `FN_CPP_ROOT` en `fn_framework`, y `add_imgui_app` añade post-build copy de la TTF junto al exe (no depende de FN_CPP_ROOT en runtime, portable).
- Hecho: path resolver en runtime busca la TTF en orden: `./tabler-icons.ttf``./assets/``$FN_ASSETS_DIR``${FN_CPP_ROOT}/vendor/tabler-icons/`. Fallback a stderr + solo texto si no la encuentra.
- Hecho: `demos_core.cpp` (gallery) — `demo_icon_button` y `demo_toolbar` migrados de hex UTF-8 a `TI_*` (12 iconos en la fila: TI_REFRESH, TI_PLUS, TI_TRASH, TI_CHEVRON_DOWN, TI_SETTINGS, TI_CHECK, TI_X, TI_PENCIL, TI_DEVICE_FLOPPY, TI_SEARCH, TI_HELP, TI_HOME). Botones text+icon: `button(TI_PLUS " New", V::Primary)`.
- Hecho: regla en `cpp/DESIGN_SYSTEM.md` seccion 11 — uso obligatorio de `TI_*`, anti-patrones (hex UTF-8, emojis, otras icon fonts), upgrade procedure, checklist.
- Hecho: notas en `cpp/functions/core/icon_button.md` (la tabla hex original queda como historica) y `cpp/apps/primitives_gallery/README.md` (`## Iconos en los demos`).
- Hecho: memoria persistente `feedback_cpp_icons.md` para futuras sesiones.
Bug + fix:
- `add_imgui_app` resolvia `${CMAKE_CURRENT_SOURCE_DIR}/vendor/tabler-icons/...` desde el dir del caller (no del root). → Capturar `FN_CPP_ROOT_DIR` con `set(... CACHE INTERNAL)` a nivel root y usarlo dentro de la funcion.
- Indexer rechazo `icon_font` como impuro sin error_type → añadido `error_type: error_go_core` (convencion cpp del registry).
Build verificado:
```bash
cd cpp/build/linux && cmake --build . --target primitives_gallery
# 100% Built target primitives_gallery
ls apps/primitives_gallery/tabler-icons.ttf # copiado post-build
```
Pendiente:
- Recompilar Windows cross (`cpp/build/windows/`) para apps que se distribuyan a /mnt/c/Users/lucas/Desktop — el `add_imgui_app` ya copia la TTF, basta `cmake --build cpp/build/windows --target <app>`.
- Auditar el resto de apps (`cpp/apps/shaders_lab/main.cpp`, `dataforge/*`) por hex UTF-8 inline o emojis y migrar a `TI_*`.
- Si el atlas completo (5093 glyphs a 14 px) resulta pesado en VRAM, recortar `tabler_ranges[]` en `icon_font.cpp` a los rangos efectivamente usados (U+EA5E..U+EC00 cubre la mayoria comun).
Reindex: 900 funciones (+1 icon_font_cpp_core), 153 types, 13 apps. Working tree con cambios sin commit.
## 16:05 — Cross-build Windows + sync a Desktop/apps
Recompilados los 3 .exe afectados por el cambio de fuentes en `app_base.cpp` y desplegados al escritorio Windows del usuario (donde ejecuta las apps nativas, ya que en WSL no hay GUI).
- Hecho: `cmake --build cpp/build/windows --target primitives_gallery registry_dashboard shaders_lab -j$(nproc)` — los 3 binarios MinGW listos en `cpp/build/windows/apps/<app>/`.
- Hecho: `add_imgui_app` ya copia `tabler-icons.ttf` junto al exe post-build (verificado, 2.7 MB en cada dir).
- Hecho: sync a `/mnt/c/Users/lucas/Desktop/apps/<app>/` para los tres apps. Estado final por dir:
- `primitives_gallery/`: `primitives_gallery.exe` (15.2 MB) + `tabler-icons.ttf`
- `registry_dashboard/`: `registry_dashboard.exe` (20.6 MB) + `tabler-icons.ttf` + `imgui.ini` (preservado)
- `shaders_lab/`: `shaders_lab.exe` (23.0 MB) + `tabler-icons.ttf` + `imgui.ini` + `shaders_lab.db` (preservados)
- Hecho: actualizada memoria persistente `feedback_no_adminlocal.md` con la convencion **WSL → Desktop/apps**: el destino canonico es `/mnt/c/Users/lucas/Desktop/apps/<app>/` (no la raiz del Desktop), y SIEMPRE hay que copiar exe + assets adyacentes (TTF). Sin la TTF los `TI_*` salen como cuadritos.
Convencion documentada (memoria + diario):
```bash
APP=shaders_lab
cmake --build cpp/build/windows --target $APP -j$(nproc)
cp cpp/build/windows/apps/$APP/{$APP.exe,tabler-icons.ttf} /mnt/c/Users/lucas/Desktop/apps/$APP/
```
Pendiente:
- Probar cada app en Windows y confirmar que los iconos `TI_*` rinden correctamente (usuario).
- Si algun app C++ futuro mete assets adicionales al lado del exe (texturas, shaders, .db seed), hay que añadirlos al cp tambien — el patron post-build de `add_imgui_app` solo cubre la TTF de Tabler.
## 16:25 — Fix regresion de tamaño + tipografia vectorial
El cambio de las 15:51 metio una regresion: `load_default_fonts(text_px=15, icon_px=14)` cargaba ProggyClean default a 15 px. ProggyClean es bitmap (13 px nativo), asi que en todas las apps el texto salia mas grande Y borroso/escalado. Ademas firma con dos parametros de tamaño distintos rompia line-height al mezclar texto+icono.
- Hecho: `icon_font.h` — firma simplificada a `void load_default_fonts(float size_px = 13.0f)`. Un solo tamaño compartido por texto e iconos = line-height uniforme.
- Hecho: `icon_font.cpp` reescrita — carga **Karla-Regular** (vectorial, 17 KB, vendoreado por ImGui en `vendor/imgui/misc/fonts/`) en lugar de ProggyClean. OversampleH=2 para nitidez. Mergea Tabler al mismo tamaño. Si Karla no se encuentra, fallback a `AddFontDefault()` (ProggyClean) para no romper la app.
- Hecho: helper `find_asset(filename, repo_subpath)` factorizado — mismo path resolver para los dos TTFs (./, ./assets/, $FN_ASSETS_DIR, ${FN_CPP_ROOT}/<subpath>).
- Hecho: nueva API `fn_ui::text_font_loaded()` ademas de `tabler_font_loaded()` para diagnostico.
- Hecho: `cpp/CMakeLists.txt` `add_imgui_app` — el post-build copy ahora copia AMBAS TTFs (Karla y Tabler) junto al exe.
- Hecho: actualizadas `cpp/functions/core/icon_font.md`, `cpp/DESIGN_SYSTEM.md` seccion 11 (path resolution), y `feedback_no_adminlocal.md` (lista completa de assets a sincronizar).
- Hecho: recompilados los 3 binarios Linux + Windows. Sincronizados a `/mnt/c/Users/lucas/Desktop/apps/<app>/` con `Karla-Regular.ttf` + `tabler-icons.ttf` al lado.
Estado final binarios Windows en Desktop/apps:
- `primitives_gallery/`: exe (15.2 MB) + Karla (17 KB) + Tabler (2.7 MB)
- `registry_dashboard/`: exe (20.6 MB) + Karla + Tabler + imgui.ini preservado
- `shaders_lab/`: exe (23.0 MB) + Karla + Tabler + imgui.ini + shaders_lab.db preservados
Pendiente:
- Probar en Windows: texto debe verse igual o mejor que antes (Karla 13 px vectorial vs ProggyClean 13 px bitmap), iconos `TI_*` renderizan.
- Si Karla no encaja (estilo poco "Geist"-like), evaluar bajar Geist Sans desde `vercel/geist-font` y vendoreara en `cpp/vendor/fonts/`. Karla es la opcion KISS (cero descarga) pero no es exactamente el espejo del frontend.
## 17:30 — Settings window con FPS toggle + font picker (todas las apps)
Texto a 13 px se sentia pequeño, y queriamos que el usuario pudiera elegir fuente/tamaño y togglear el FPS overlay sin recompilar. Implementado un sistema de settings reutilizable por todas las apps C++ del registry.
- Hecho: nueva funcion `app_settings_cpp_core` (impure, error_go_core) — estado global `AppSettings { show_fps, font_id, font_size_px }`, persistencia en `<cwd>/app_settings.ini`, ventana flotante con `CollapsingHeader` para Display + Typography + secciones extra registrables, auto-save al cambiar.
- Hecho: API publica:
- `settings()` → ref mutable
- `settings_load() / settings_save()` → INI I/O
- `settings_window_set_open(bool) / toggle()`
- `settings_window_menu_item("Settings...")` → MenuItem componible
- `settings_window_render()` → render no-op si cerrada
- `settings_window_add_section(id, title, callback)` → extender desde apps
- `settings_mark_font_dirty() / consume_font_dirty()` → coordinacion con icon_font
- Hecho: `icon_font` reescrita — `load_fonts_from_settings()` lee `font_id` del settings y carga la TTF correspondiente (Karla / Roboto / DroidSans / Cousine / ProggyClean). Default global `font_size_px = 15` (antes 13, se sentia pequeño).
- Hecho: `app_base.cpp` orquesta:
1. `settings_load()` antes de cargar fuentes
2. `load_fonts_from_settings()` aplica el font del .ini
3. Cada frame: si `consume_font_dirty()`, `io.Fonts->Clear()` + reload (ImGui 1.92+ refresca GPU texture solo via `UpdateTexture`)
4. Despues de `render_fn()`: `settings_window_render()` (no-op si cerrada)
5. Si `settings().show_fps`: `fps_overlay()`
6. Al exit: `settings_save()`
- Hecho: `app_menubar` añade siempre el MenuItem "Settings..." como tercer item (junto a View / Layouts).
- Hecho: `fn_framework` (libreria static) ahora incluye `tokens.cpp + icon_font.cpp + app_settings.cpp + fps_overlay.cpp + panel_menu.cpp + layouts_menu.cpp + app_menubar.cpp`. Cualquier app que use `add_imgui_app` los enlaza automaticamente. Removidos de los CMakeLists individuales para evitar multiple-definition (shaders_lab, registry_dashboard, gallery, chart_demo).
- Hecho: gallery + dashboard ahora llaman `fn_ui::app_menubar(nullptr, 0, nullptr)` para exponer Settings (no tienen paneles ni layouts propios).
- Hecho: shaders_lab — removida llamada explicita a `fps_overlay()` en panel Controls. Ahora siempre se respeta el toggle de Settings.
- Hecho: `add_imgui_app` post-build copia las 4 TTFs vectoriales (Karla 17 KB, Roboto 163 KB, DroidSans 190 KB, Cousine 44 KB) + Tabler (2.7 MB) junto a cada exe.
- Hecho: `cpp/DESIGN_SYSTEM.md` seccion 12 nueva — Settings (UI, persistencia, extension, anti-patrones).
- Hecho: `app_settings.md` con docs completas en el registry.
Bug + fix:
- Build inicial fallo: `ImGui_ImplOpenGL3_DestroyFontsTexture/CreateFontsTexture` no existen en ImGui 1.92+ (renombrados/removidos). Fix: dejar que la atlas se recree y el backend la actualice solo via `UpdateTexture` en `NewFrame()`. Mas simple ademas.
Pendiente:
- Cerrar `primitives_gallery.exe` en Windows: el .exe esta locked y no se sincronizo (TTFs si). Reintentar `cp` cuando la app este cerrada.
- Probar en Windows que el menu Settings... abre la ventana, que cambiar fuente/tamaño rebuildea atlas en el siguiente frame, que toggle FPS funciona, que `app_settings.ini` se crea junto al exe con los valores correctos.
- Si una app quiere settings propios (shaders_lab podria querer "auto-compile on save"), ejemplo de uso en `app_settings.md`.
Reindex: 901 funciones (+1 app_settings_cpp_core), 153 types, 13 apps. Working tree con cambios sin commit.
## 17:50 — Settings menubar en chart_demo + gallery resync
- Hecho: `chart_demo/main.cpp` — removida llamada explicita a `fps_overlay()`, añadida `fn_ui::app_menubar(nullptr, 0, nullptr)` para exponer Settings (mismo patron que gallery y dashboard).
- Hecho: removido `#include "core/fps_overlay.h"` (ya no necesario en la app — vive en fn_framework).
- Hecho: build Linux + Windows OK. Gallery resynced (`primitives_gallery.exe` 15.2 MB, timestamp 20:06).
- Hecho: nueva carpeta `Desktop/apps/chart_demo/` con `chart_demo.exe` (14.9 MB) + 5 TTFs.
Estado final apps deployed con Settings menubar + multi-font:
- `Desktop/apps/primitives_gallery/`
- `Desktop/apps/registry_dashboard/`
- `Desktop/apps/shaders_lab/`
- `Desktop/apps/chart_demo/` ✓ (nueva)
Las 4 apps comparten la misma menubar pattern (`View` opcional, `Layouts` opcional, `Settings...` siempre) y la misma seleccion de fuente/tamaño + toggle FPS via Settings.
## 18:10 — Fix: cambio de tamaño en runtime ahora es instantaneo
Usuario reportaba que el slider de tamaño no aplicaba inmediatamente. Causa: rebuild de atlas (Clear + AddFont + UpdateTexture) tarda 1+ frame y se notaba lag/flicker.
ImGui 1.92+ (junio 2025) introdujo el sistema **escalable**: `style.FontSizeBase` cambia el tamaño de render dinamicamente sin rebuild de atlas — el atlas se rasteriza una vez y se escala via vector at draw time (cuando `BackendFlags_RendererHasTextures` esta activo, que lo esta con el backend OpenGL3 nuevo).
- Hecho: `app_base.cpp` cada frame: `style.FontSizeBase = settings().font_size_px` + `style._NextFrameFontSizeBase = ...` (FIXME-hack documentado en imgui_demo.cpp:8520). Tamaño cambia al instante sin rebuild.
- Hecho: `settings_window`: el slider/combo de Size ya NO marca font dirty. Cambio puro de `font_size_px` (sin cambio de `font_id`) NO rebuildea atlas.
- Hecho: cambio de `font_id` (TTF distinta) sigue rebuildeando atlas — necesario porque las metricas de glyph difieren entre TTFs.
- Hecho: inicializacion en `run_app`: `style.FontSizeBase = settings().font_size_px` justo despues de `load_fonts_from_settings()`, asi el primer frame ya respeta el .ini.
- Hecho: footer de la ventana actualizado: "Tamaño aplica al instante. Cambio de fuente = 1 frame.".
- Hecho: rebuild Linux + Windows OK. Las 4 .exe sincronizadas a `Desktop/apps/` (timestamp 20:12).
Referencias en imgui:
- `imgui.cpp:439` — changelog 1.92.6 sobre escalado dinamico
- `imgui.h:2370` — comment de `FontSizeBase`
- `imgui_demo.cpp:8519-8520` — patron de slider sobre `style.FontSizeBase` + `_NextFrameFontSizeBase`
## 18:30 — Defaults DroidSans 15, kpi_card v1.3 con icono, shader_canvas en gallery
Tres cambios en un sweep:
### Defaults globales
- Hecho: `AppSettings::font_id = FontId::DroidSans` (antes Karla). DroidSans tiene mejor legibilidad solida a 15 px en ImGui sin hinting.
- Hecho: `font_size_px = 15` y `show_fps = false` confirmados como defaults.
- Comentario actualizado en `app_settings.cpp` para que el .ini deje claro cual es el default.
### kpi_card v1.3.0 — icono + Tabler arrows
- Hecho: nueva firma con parametro opcional al final: `kpi_card(label, value, delta, history, count, format, icon = nullptr)`. Icono se renderiza inline antes del label en text_muted.
- Hecho: arrows del delta migradas de UTF-8 hex (`\xe2\x96\xb2` / `\xe2\x96\xbc`) a `TI_TRENDING_UP` / `TI_TRENDING_DOWN` — los anteriores no estan en el atlas de DroidSans/Karla y salian como cuadritos. Mismo fix en el placeholder de "no data": `\xe2\x80\x94` (em dash) → `TI_MINUS`.
- Hecho: card altura 78 → 86 px para acomodar el row icono+label sin apretar el resto.
- Hecho: gallery demo actualizado con iconos: `TI_CASH` (Revenue), `TI_USERS` (Users), `TI_CHART_BAR` (Churn), `TI_ALERT_CIRCLE` (Errors).
- Hecho: `kpi_card.md` bumped a v1.3, frontmatter con nuevo param `icon`.
### shader_canvas en primitives_gallery
shaders_lab tiene como pieza distintiva el preview live de fragment shaders. Añadido como demo en la gallery para documentar/showcase.
- Hecho: nuevo dominio "Gfx" en el sidebar, primer item: `shader_canvas`.
- Hecho: `demos_gfx.cpp` con un fragment shader sintetico (gradiente animado de celdas con focus en mouse), compilado en el primer frame con `compile_fragment` y renderizado a 480x300 px via `canvas_render(canvas, time)`.
- Hecho: `demos.h` registra `demo_shader_canvas`. `main.cpp` añade entry al array `k_demos[]` con categoria "Gfx".
- Hecho: `gallery/CMakeLists.txt` añade el shader stack: `gl_shader.cpp + gl_framebuffer.cpp + fullscreen_quad.cpp + shader_canvas.cpp + demos_gfx.cpp`.
- Estado del binario: gallery crece de 15.2 → 18.1 MB (shader stack).
### Build + sync
- Hecho: rebuild Linux + Windows OK.
- Hecho: `Desktop/apps/` resynced — los 4 exes a las 20:20 con la nueva default config (DroidSans 15) y los iconos renderizando en kpi_card.
Pendiente:
- Probar en Windows que defaults aplican en la primera apertura (sin `app_settings.ini` previo): DroidSans 15, FPS off.
- Probar shader_canvas demo en gallery: el shader debe compilar y animarse.
- Considerar mas demos gfx: `dag_palette` / `dag_panel` (node editor) — mas trabajo, lo dejo para otra sesion si hace falta.
- Añadir `app_menubar` / `panel_menu` / `layouts_menu` / `app_settings` como demos explicitos en la gallery (ahora se ven via la propia menubar de la gallery, pero un demo dedicado documentaria mejor el API). Skip por ahora.
Reindex: 901 funciones (kpi_card y app_settings ya estaban en sesiones previas), 153 types.
## 20:43 — /documentar — cierre de sesion C++ icons + settings + fuentes
Wrap-up: distribucion de la conversacion a los `.md` que faltaban tras todos los cambios C++ del dia.
- Hecho: `cpp/functions/core/app_menubar.md` — bloque "Notas — Settings menu" describiendo la inclusion automatica del item `Settings...` y la dependencia implicita en `app_settings_cpp_core`.
- Hecho: `cpp/functions/core/fps_overlay.md` — bloque "Notas — Auto-render via app_settings": `fn::run_app` lo invoca segun `settings().show_fps`; anti-patron de llamarlo directo desde la app.
- Hecho: `cpp/functions/viz/kpi_card.md` — bumped a v1.3, nuevo param `icon`, glyphs Tabler en delta/placeholder, comentario obsoleto sobre rangos UTF-8 marcado.
- Hecho: `apps/shaders_lab/app.md` — bloque "Notas — Settings + iconos" + "Lo siguiente que pega" (auditar hex inline en uniform_panel/dag_panel; ejemplo de seccion extra de settings).
- Hecho: `projects/fn_monitoring/apps/registry_dashboard/app.md` — bloque "Notas — Settings menubar" con el cambio de `render()` (ahora llama `app_menubar(nullptr,0,nullptr)`) y limpieza de CMake.
- Hecho: reindex final → 901 funciones, 153 types, 13 apps.
Pendiente para proxima sesion:
- Migrar a `TI_*` cualquier hex UTF-8 (`"\x..\x.."`) o emoji Unicode hardcoded en uniform_panel, dag_panel, dag_node_editor (apps en uso ya tienen Tabler en atlas, no estamos aprovechando).
- Demos extra en gallery: `app_menubar`, `app_settings` y/o un par de items del DAG (`dag_palette` mostrando la paleta drag-source). Skip esta sesion porque requieren state pesado.
- Ejemplo concreto de `settings_window_add_section` en `shaders_lab` (auto-compile + debounce_ms persistido en `shaders_lab.db`).
Estado final del working tree: cambios sin commit. Las 4 .exe en `Desktop/apps/` con build de las 20:20 (DroidSans 15 default, kpi cards con icono, gallery con shader_canvas demo).