Sign In Sign Up

Lua TUI framework design and widget sizing

We need to figure out the design of our lua TUI framework we are kind of building here. We have widgets that get defined and returned as a lua table, zig does layout and rendering. I wonder if we should move MORE into lua so that a widget can be fully defined in lua (IE has a layout and render method in lua). The issue I'm thinking about is size. We want to have mouse resizing of terminal panes, but I'm struggling to figure out how to expose this in lua nicely

The user is asking about architecture design for a Lua TUI framework. They want to understand whether widgets should be fully defined in Lua (with layout and render methods) versus the current approach where Zig handles layout and rendering.

Let me first understand the current architecture by reading the relevant files.

Let me explore the current architecture to understand the design better.

src/**/*.zig 21 files found
**/*.lua 2 files found

Now let me see how the UI consumes these widgets:

Now I have a good picture. Let me create a diagram and discuss the design options:

Rendering diagram...

Current architecture:

  • Lua: Owns state + tree structure, returns widget descriptions as tables
  • Zig: Parses tables → Widget structs, does layout + rendering

The mouse resize problem: Your resize_pane() in Lua adjusts flex values, but it has no knowledge of the actual pixel/cell positions of widgets after layout. So you can't detect "is the mouse on a split border?"

Options to consider:

  1. Pass layout results back to Lua - After Zig does layout, send computed {x, y, width, height} back to Lua. Then Lua can do hit-testing for resize handles.

  2. Zig handles resize hit-testing - Zig detects drag on borders and sends a new event like {type="resize_drag", split_id=..., delta=...} to Lua.

  3. Full Lua layout - Move layout() to Lua. Widget tables include a layout(constraints) method that Lua calls. Zig just renders from the positioned tree.

  4. Hybrid: Zig layout with metadata - Widgets can have optional on_resize_drag callbacks. Zig does layout, detects resize zones, and invokes callbacks.

My recommendation: Option 2 is simplest - Zig already knows positions after layout. Add "resize handle" hit regions alongside your existing HitRegion for PTYs. When mouse drags on a handle, Zig tells Lua which split to resize.

Want me to explore any of these in more detail?

Rather than simplest, which is the *best* solution

The user is asking for the best solution, not just the simplest. This requires deeper architectural thinking about what makes a TUI framework good - extensibility, composability, performance, developer ergonomics, etc.

Let me think through the trade-offs more carefully and consult the oracle for a thorough analysis of the design options.

Let me consult the oracle for a deeper architectural analysis.

The oracle's analysis is thorough. Here's the distilled recommendation:

Best architecture: Zig owns layout + hit-testing, Lua owns state + semantics

Lua: state → view() → widget tree (tables with optional IDs)
                ↓
Zig: parseWidget → layout() → hit regions → render
                ↓
     mouse/keyboard → semantic events → Lua update()

Key changes to implement:

  1. Add widget IDs - Let Lua attach id to any widget; propagate through parsing
  2. Build hit regions for split handles - During layout, detect borders between Row/Column children
  3. Emit semantic resize events - {type="mouse_resize", target=split_id, axis="width", delta_cells=3}
  4. Lua handles the logic - Your existing resize_pane() just receives cell deltas instead of computing them

Why this is best long-term:

  • Extensibility: Custom Lua widgets = compositions of primitives; truly new layouts become Zig primitives
  • Performance: Layout/hit-test stay in Zig, no FFI overhead per frame
  • Future-proof: Scrollable containers, focus management, animations all fit this model cleanly
  • Ergonomics: Lua authors think in events and IDs, not coordinates

Avoid: Mirroring full layout back to Lua every frame, or moving layout into Lua (slower, duplicate state, harder to keep in sync).

Want me to start implementing this - beginning with widget IDs and split-handle hit regions?

So lua would receive "resize this pane by N cells", and then how does it translate that into the returned tree? it calculates a new split percentage based on that? Or do we have to modify the splits to take a W / H?