Implements "Active Request" pattern for cursor animation:
- Add requested_cursor_blink flag to Context (reset each frame)
- Add requestCursorBlink() function for widgets to call
- needsCursorAnimation() now returns false if no widget requested it
- TextInput calls requestCursorBlink() when focused and editable
- CellEditor calls requestCursorBlink() when editing
This eliminates unnecessary redraws when no cursor is visible
(e.g., in Config tab with tables but no active text input).
Also raised CURSOR_BLINK_PERIOD_MS from 300ms to 600ms (GTK/Linux standard).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
GTK/Linux standard rate. Reduces unnecessary redraws by ~50%.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
VirtualAdvancedTable ya NO gestiona tips internamente.
El carrusel ahora vive en zsimifactu/StatusLine (v2.0).
Eliminado:
- table_tips[] y TIP_ROTATION_FRAMES de types.zig
- Re-exports de table_core.zig
- frame_count y tip_index de VirtualAdvancedTableState
- current_tip de VirtualAdvancedTableResult
- Lógica de rotación (frame_count % TIP_ROTATION)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Añade derived_bg al resultado de drawPanelFrame para que los paneles
puedan usar el color exacto del fondo para las tablas (mimetismo visual).
Las tablas deben usar frame_result.derived_bg como row_normal para
integrarse visualmente con el panel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problema: Al hacer clic en un tab, el dibujo visual mostraba el
tab viejo como activo porque is_selected se calculaba ANTES de
procesar el clic.
Solución: Separar en dos passes:
- Pass 1: Detectar clics y actualizar state.selected
- Pass 2: Dibujar con el estado ya actualizado
Esto elimina el "parpadeo" donde el tab visual no coincidía
con el tab lógico durante un frame.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Nueva API BevelStyle para control fino de efectos 3D:
- effect: raised (elevado) o sunken (hundido)
- inset: 0 (exterior) o 1 (interior)
- light_top, light_left: intensidad de luz por borde
- dark_bottom, dark_right: intensidad de sombra por borde
- use_hsl: HSL (true) o RGB (false)
Presets incluidos:
- BevelStyle.raised_inset (default, botones)
- BevelStyle.sunken_inset (botones presionados)
- BevelStyle.raised_outer (estilo Windows 95)
- BevelStyle.sunken_outer (estilo Windows 95)
API:
- ctx.drawBevel(x, y, w, h, color, style) - nueva función principal
- ctx.drawBeveledRect() - wrapper compatibilidad (usa raised_inset)
- ctx.drawBeveledRectPressed() - wrapper compatibilidad (usa sunken_inset)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Event.KeyEvent ahora re-exporta Input.KeyEvent (unificación tipos)
- Añadir burst_sensitive a PanelInfo (para supresión ráfagas)
- Exportar Panel, PanelInfo, Zone, Event, makePanel desde raíz
- Mantener aliases WindowPanel/WindowPanelInfo para compatibilidad
Esta unificación permite que zsimifactu use WindowState de zcatgui
directamente, ya que Panel y Event son ahora el mismo tipo.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sistema de ventanas dinámicas donde:
- Panel interface usa app_ctx: ?*anyopaque (desacoplado)
- WindowState gestiona lista de paneles con BoundedArray(8)
- El ID del panel viaja con el panel (elimina errores de mismatch)
- Focus groups encapsulados con base_focus_group
Exports:
- WindowState, WindowPanel, WindowPanelInfo, makeWindowPanel
- window module completo
Parte de refactorización consensuada (R.Eugenio, Claude, Gemini)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Optimización 2.3 del plan de rendimiento:
- fillRect para alpha=255 usa vectores SIMD explícitos
- Escribe 8 pixels (256 bits) por iteración en lugar de 1
- Remainder loop para los últimos 0-7 pixels
- Mantiene el path de blending para alpha<255
Beneficio esperado: 5-10x más rápido para rectángulos grandes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
El check anterior estaba DESPUÉS del lerpU8, causando loop infinito:
- lerpU8 trunca incrementos <1, current no cambia
- dr = |current - target| sigue siendo > 1 (ej: 10)
- return true → pide más frames
- Repeat forever
Nuevo algoritmo:
1. Calcular diferencia PRIMERO
2. Si diferencia <= 2 en todos los canales → snap directo
3. Solo hacer lerp si diferencia > 2
Umbral aumentado de 1 a 2 para mayor margen de seguridad.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problema: lerpU8 truncaba incrementos <1, causando que las animaciones
nunca terminaran. Con delta_ms=16ms y duration=500ms, el factor t=0.032
hacía que diferencias de 1 (ej: 99→100) nunca convergieran.
Solución: Añadir epsilon check después del lerp. Si la diferencia en
cada canal RGBA es ≤1, forzar snap al target y devolver false.
Esto elimina los redraws infinitos en idle reportados por el usuario.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- FrameStats: nuevo campo executed_cmds para comandos realmente ejecutados
- SoftwareRenderer: contador que se incrementa en execute()
- Métodos resetExecutedCount() y getExecutedCount()
- CLAUDE.md: sección OPTIMIZACIONES DE RENDIMIENTO documentada
Permite comparar Total (generados) vs Exec (ejecutados) para
diagnosticar efectividad del dirty regions filtering.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fillRect: disable runtime safety for hot path (bounds pre-validated)
- drawGlyphBitmap: disable runtime safety for hot path
- Context: add burst detection (isSelectionBurstActive, markNavigationEvent)
- PanelFrameConfig: add burst_sensitive field
- PanelFrameResult: new struct for frame drawing results
Note: burst_sensitive mechanism available but not actively used
(causes visual flickering when suppressing panel content)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Nuevo flag para "Dibujo Fantasma":
- suppress_commands: bool en Context
- pushCommand() y pushOverlayCommand() retornan si está activo
- Permite procesar input (draw) sin generar comandos (ahorra CPU)
Solución de Gemini para immediate-mode + dirty panels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clarificar el uso de SDL_RENDERER_PRESENTVSYNC:
- Sincroniza con refresco del monitor (60Hz)
- Elimina screen tearing
- Reduce consumo CPU/GPU
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Añade el sistema de dirty panels para optimización de rendering:
- panel_areas: HashMap para registrar rectángulos de paneles
- dirty_panels: HashMap con flags de invalidación por panel
- registerPanelArea(id, rect): Registrar panel con nombre
- invalidatePanel(id): Marcar panel como dirty
- isPanelDirty(id): Consultar si necesita redraw
- markAllPanelsDirty(): Para resize/tab change
- getDirtyPanelRects(): Obtener rects dirty para renderer
- clearDirtyPanels(): Limpiar flags (automático en endFrame)
Diseño:
- La aplicación registra paneles al inicio
- La aplicación notifica cambios via invalidatePanel()
- El renderer usa getDirtyPanelRects() para limpieza selectiva
- Los flags se limpian automáticamente en endFrame()
Parte de la implementación de Dirty Panels Fase 1.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cambios en deriveDarkPalette y derivePanelFrameColors:
- focus_blend: 80 → 70 (30% color visible, antes 20%)
- unfocus_blend: 88 → 80 (20% color visible, antes 12%)
Objetivo: Mejor identificación visual de tipos de documento/cliente
sin perder la estética oscura profesional.
Tests actualizados para reflejar nuevos valores.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Tiempo de aparición ahora es aleatorio entre 45s y 3 minutos
- Cada aparición genera nuevo umbral para la siguiente
- Mantiene el efecto sorpresa
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- drawBeveledRect: bordes ahora en x+1,y+1 (interior del rect)
- drawBeveledRectPressed: mismo fix para estado presionado
- inner_w/inner_h calculados como w-2/h-2 para correcta insetación
- Fix identificado en verificación MASTER_RESCATE punto C
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Título: x+28 para dejar espacio al semáforo (antes x+10)
- Semáforo: "Viendo ■" alineado a la derecha (antes ■ izquierda, texto derecha)
- Botones: visual_adjust +2px para compensar baseline TTF
- contrastTextColor como fallback para títulos sin base_color
Layout final: "[N] Título Estado ■"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix legibilidad títulos:
- title_color: 85% soft_white + 15% tinte del base_color
- Antes: base.lightenHsl(90) → azul claro sobre azul oscuro (ilegible)
- Ahora: blanco con tinte sutil → máximo contraste + identidad visual
Fix centrado vertical botones:
- Añadido char_height al Context (default 14px para TTF)
- button.zig: usa char_height en vez de char_width
- Offset visual -1px para compensar efecto 3D del bisel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V5 - Títulos Adaptativos:
- derivePanelFrameColors: title_color según luminosidad del fondo
- Fondo oscuro (L < 0.5) → base.lightenHsl(90) (blanco teñido)
- Fondo claro → base.darkenHsl(90) (negro teñido)
- drawPanelFrame: siempre usa title_color (no border_unfocus)
- Márgenes título mejorados: x+10, y+5
Resultado: máximo contraste y legibilidad en todos los paneles.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ajuste consensuado:
- deriveDarkPalette: 80% black (20% color) focus, 88% black (12% color) unfocus
- derivePanelFrameColors: mismos valores
- Elimina compensación perceptual completamente
Unfocus 12% es más visible que el anterior 4%.
Simplificación consensuada:
- Eliminar compensación perceptual (causaba más problemas)
- Blend fijo para TODOS los colores:
- Focus: 18% base / 82% negro
- Unfocus: 6% base / 94% negro
La fluidez viene de pasar bg_transition.current a widgets,
no de compensar matemáticamente.
Corrección de rumbo consensuada:
- Colores brillantes (L > 0.2): 22% intensidad (estándar del rojo)
- Colores oscuros (L <= 0.2): 35% intensidad (boost para azul/violeta)
El objetivo es que todos los paneles tengan la vibrancia del rojo.
El azul debe 'saltar' del negro tanto como lo hace el rojo.
Added extensive documentation explaining:
- The problem (blue goes to black, red stays red when darkened)
- Technical cause (ITU-R BT.709 luminance formula)
- Solution (threshold 0.15, correction factor)
- How to disable if needed
Status: PENDING CONSENSUS - needs team input on colors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed threshold from 0.45 to 0.15 so that:
- Blue (~0.07 luminance) gets boost to avoid "goes to black" effect
- Red (~0.21 luminance) is NOT affected (already darkens nicely)
This fixes the issue where red panels became too saturated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The current implementation boosts red colors when it should
compensate blue colors instead. Disabled until the algorithm
is revised.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PanelFrameConfig struct with has_focus, focus_bg, unfocus_bg, border_color options
- Add drawPanelFrame() method that encapsulates common panel rendering pattern:
1. Update ColorTransition and request animation frame if needed
2. Draw shadow when focused
3. Draw beveled background
4. Draw border outline
- Export ColorTransition from context module
- Reduces ~15 lines of repeated code per panel to single function call
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bevel: bool option to TabsConfig (default false)
- Active tabs: raised effect (light top/left, dark bottom/right)
- Inactive tabs: subtle inset for depth contrast
- Respects tab_bg color for bevel calculations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
E1 task from PLAN_REFINAMIENTO_UI_2025-12-30.md:
- Add Color.perceptualLuminance() using ITU-R BT.709 weights
- Add global perceptual_correction_enabled flag (default: true)
- deriveDarkPalette/deriveLightPalette now boost low-luminance colors
- Colors like red/magenta now have comparable contrast to blue
- Correction capped at 0.7 to avoid excessive boost
Algorithm: if base_lum < 0.45, reduce blend % by ratio (more color visible)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Allow panels to specify custom focus ring color.
- TextInputConfig.focus_border_color: overrides theme.primary
- SelectConfig.focus_border_color: same pattern
- Uses Command.focusRingColor() instead of focusRing()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- button.zig: Usar ctx.measureText() y ctx.char_width para centrado
- label.zig: Mismo fix para centrado de labels
- animation.zig: Actualizar test ColorTransition para duration 500ms
Z-Design V2: El centrado ahora funciona correctamente con TTF fonts.
Antes usaba 8px hardcodeado, ahora usa métricas dinámicas del contexto.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ColorTransition: 200ms → 500ms (transiciones más perceptibles)
- deriveDarkPalette: 4%/20% base color (mayor contraste focus/unfocus)
- deriveLightPalette: 1%/6% base color (proporcional)
- Context: añadir requestAnimationFrame/needsAnimationFrame
- Tests actualizados para nuevos umbrales
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Chips de filtro con corner_radius: 4 (igual que botones)
en lugar de 11 (pill-like).
Esto hace que chips y botones tengan el mismo lenguaje visual.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Scrollbars más anchos para mejor usabilidad.
- list.zig: 8→14px
- grid.zig: 8→14px
- advanced_table/drawing.zig: 12→14px
- virtual_advanced_table/drawing.zig: 12→14px
- virtual_scroll.zig: 12→14px (default config)
- table/render.zig: 12→14px
El bisel interno Laravel ya estaba implementado en drawBeveledRect.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Botones más compactos para look más elegante.
- ActionButtonsOpts.button_height: 28 → 22
- NavButtonsOpts.button_height: 28 → 22
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Añade rectángulo de fondo con row_normal color ANTES de dibujar
las filas. Esto asegura que:
- Tablas vacías muestren color de fondo correcto (no negro)
- Áreas debajo de las últimas filas no queden sin pintar
VirtualAdvancedTable ya tenía este comportamiento.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refinamiento Visual Premium:
- Dark mode fondo_sin_focus: negro puro → 7% base color
- Dark mode fondo_con_focus: mantiene 15% base color
- Light mode sincronizado: 1%/3% base color
Efecto: Los paneles siempre tienen su "identidad" de color,
incluso sin focus. El cambio de focus es ahora una transición
suave de "iluminación" en vez de un fogonazo negro→color.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>