Files

32 KiB
Raw Permalink Blame History

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.

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_corestd::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/reindexexec.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).

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:

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):

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}/).
  • 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.

  • 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

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.

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).