-
Notifications
You must be signed in to change notification settings - Fork 4
Advanced
Everything else in this wiki teaches the RetUI API—Box, UseState, Focus, and other components.
This page is different.
It explains how RetUI works internally.
You don't need to know these details to build applications, but they are useful if you:
- Want to contribute to RetUI
- Need to debug performance issues
- Want to understand how rendering works
- Are curious about how RetUI is built
RetUI has four internal layers:
Your Component Tree (Elements)
│
▼
Layout Engine
│
▼
Renderer
│
▼
Screen
▲
│
Runtime
Each layer has a specific responsibility.
Every component you create eventually becomes a retui.Element.
For example:
retui.Text("Hello", retui.NewStyle())or
retui.Box(...)These functions don't draw anything directly.
Instead, they build an Element Tree.
Example:
Box
├── Text
├── Button
└── Input
Think of the Element Tree as a blueprint describing what should appear on the screen.
Every render creates a brand new tree.
The Runtime is the heart of every RetUI application.
It is responsible for:
- Reading keyboard input
- Detecting terminal resize
- Running timers
- Triggering rendering
- Executing effects
Unlike a game engine, RetUI does not continuously redraw the screen.
It only renders when something changes.
For example:
- A key is pressed
- The terminal is resized
- A timer fires
- State changes
This event-driven approach keeps applications efficient.
When something changes, RetUI renders the application.
The rendering process can happen in multiple passes.
Your component function runs.
During this pass:
- Keyboard events are processed.
- State can change.
- Hooks execute.
Nothing is drawn yet.
The component runs again.
This time it uses the updated state.
The final Element Tree is created.
The Renderer then paints the UI.
After rendering, UseEffect() callbacks run.
If an effect changes state, RetUI immediately performs one more render.
Otherwise, rendering stops.
Imagine a simple counter.
Count: 5
The user presses Enter.
During Pass 1:
setCount(6)The state changes.
During Pass 2:
Count: 6
The updated value is rendered.
Without multiple passes, the UI would always be one step behind.
Once the Element Tree is ready, the Layout Engine calculates where every element belongs.
Example:
+------------------------------+
| Header |
+------------------------------+
| Sidebar | Content |
| | |
+------------------------------+
The Layout Engine calculates:
- X position
- Y position
- Width
- Height
Each element receives its own rectangle.
The Renderer uses this information to draw everything correctly.
The Renderer converts the Element Tree into terminal cells.
It performs three steps.
The Element Tree is converted into a Layout Tree.
Each element determines its preferred size.
The Layout Engine calculates the position and size of every element.
Finally, every character is written into an internal screen buffer.
Nothing is sent to the terminal yet.
The Screen manages everything related to the terminal.
Its most important job is diffing.
Instead of redrawing the entire screen, it only updates what changed.
Example:
Before
Counter: 5
After
Counter: 6
Only the character 5 is replaced with 6.
Everything else stays exactly the same.
This makes RetUI very efficient.
RetUI keeps two screen buffers.
Current Frame
Previous Frame
After rendering, the two buffers are compared.
Only the differences are written to the terminal.
This technique is known as double buffering.
RetUI also tracks which part of the screen changed.
Instead of checking every cell, it only updates the affected area.
Example:
+----------------------------+
| |
| Changed Area |
| |
+----------------------------+
This further improves rendering performance.
All terminal output is buffered before being written.
Instead of sending hundreds of small updates, RetUI combines everything into a single write whenever possible.
This reduces system calls and improves performance.
The complete rendering process looks like this.
User presses a key
│
▼
Runtime receives the event
│
▼
Component renders
│
▼
State updates
│
▼
Component renders again
│
▼
Layout Engine calculates layout
│
▼
Renderer paints the screen buffer
│
▼
Screen compares old and new frames
│
▼
Only changed cells are written
│
▼
Terminal updates
RetUI avoids unnecessary work.
It only renders when something changes.
It only redraws changed areas.
It only writes changed characters.
Because of this, even large terminal applications remain responsive.
RetUI is built around four main components.
| Component | Responsibility |
|---|---|
| Runtime | Handles events and controls rendering |
| Layout Engine | Calculates positions and sizes |
| Renderer | Converts elements into terminal cells |
| Screen | Updates only the changed cells |
The important thing to remember is this:
Your components never draw directly to the terminal.
They simply describe what the UI should look like.
RetUI takes care of layout, rendering, diffing and terminal updates automatically.