Skip to content
Subha Sundar Das edited this page Jul 14, 2026 · 1 revision

Advanced: Runtime, Renderer & Screen

Everything else in this wiki teaches the RetUI APIBox, 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.


The Element Tree

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.


Runtime

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.


The Render Process

When something changes, RetUI renders the application.

The rendering process can happen in multiple passes.

Pass 1

Your component function runs.

During this pass:

  • Keyboard events are processed.
  • State can change.
  • Hooks execute.

Nothing is drawn yet.


Pass 2

The component runs again.

This time it uses the updated state.

The final Element Tree is created.

The Renderer then paints the UI.


Pass 3 (Optional)

After rendering, UseEffect() callbacks run.

If an effect changes state, RetUI immediately performs one more render.

Otherwise, rendering stops.


Why Multiple Passes?

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.


Layout Engine

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.


Renderer

The Renderer converts the Element Tree into terminal cells.

It performs three steps.

1. Build the Layout Tree

The Element Tree is converted into a Layout Tree.

Each element determines its preferred size.


2. Calculate the Layout

The Layout Engine calculates the position and size of every element.


3. Paint

Finally, every character is written into an internal screen buffer.

Nothing is sent to the terminal yet.


Screen

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.


Double Buffering

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.


Dirty Regions

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.


Efficient Terminal Output

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.


What Happens When You Press a Key?

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

Why Is RetUI Fast?

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.


Summary

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.

Clone this wiki locally