Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Rikitav/Terminality/llms.txt

Use this file to discover all available pages before exploring further.

DispatchTimer is the engine’s frame clock. Each iteration of the render loop calls Tick(), which measures the elapsed time since the previous call, stores it as DeltaTime, and fires TickEvent with that value. Subscribing to TickEvent is the standard way to animate properties, poll state, or run any logic that should repeat at the frame rate. A second event, ResizeFinishedEvent, fires after the terminal window stops being resized, giving you a clean moment to re-measure layouts.

Class: DispatchTimer

DispatchTimer is a non-copyable singleton; obtain the instance with DispatchTimer::Current().

Current

static DispatchTimer& Current();
Returns the process-wide DispatchTimer instance.

TickEvent

Event<float> TickEvent;
Fired once per frame with the delta time in seconds since the last tick. Subscribe using +=:
DispatchTimer::Current().TickEvent += [](float dt)
{
    // dt is seconds elapsed since the previous frame
};
Handlers run synchronously inside Tick(), on the engine’s render thread.

ResizeFinishedEvent

Event<> ResizeFinishedEvent;
Fired after the terminal window finishes resizing. Terminality debounces resize signals with a 100 ms delay (RESIZE_DELAY = 0.1f); ResizeFinishedEvent fires on the first tick after that delay expires. Use it to invalidate custom layout measurements that depend on absolute terminal dimensions.
DispatchTimer::Current().ResizeFinishedEvent += []()
{
    // Terminal dimensions have stabilized — safe to re-query Width/Height
};

DeltaTime

float DeltaTime() const;
The delta time from the most recent Tick() call, in seconds. The same value that is passed to TickEvent handlers. Valid after the first Tick() and zero before Start() is called.
return
float
Seconds elapsed between the last two frames.

TotalTime

float TotalTime() const;
Accumulated sum of all DeltaTime values since Start() was called — effectively the wall-clock time in seconds since the application loop began.
return
float
Total elapsed time in seconds since the timer was started.

IsRunning

bool IsRunning() const;
Returns true after Start() has been called and before Stop() is called. Tick() is a no-op when the timer is not running.
return
bool
true if the timer is currently running.

IsResizing

bool IsResizing() const;
Returns true during the debounce window after a terminal resize event arrives and before ResizeFinishedEvent fires.
return
bool
true while a resize is being debounced.

Start and Stop

void Start();
void Stop();
Start records the current high-resolution time as the baseline for the first delta. Stop sets the running flag to false so subsequent Tick() calls are no-ops. The engine calls these automatically around RunUILoop; application code rarely needs to call them directly.

Tick

void Tick();
Called by the engine each frame. Computes deltaTime_ as the duration since lastTime_, accumulates it into totalTime_, fires TickEvent, and advances the resize debounce timer if a resize is in progress. Calling Tick() when IsRunning() is false is a no-op.

GetRemainingFrameTime

std::chrono::milliseconds GetRemainingFrameTime(int targetFPS = 60);
Returns how many milliseconds remain in the current frame budget at the given target frame rate. The engine uses this to sleep between frames and cap CPU usage. Returns zero if the frame has already overrun its budget.
targetFPS
int
default:"60"
Target frames per second used to calculate the per-frame budget.
return
std::chrono::milliseconds
Remaining time in the current frame, clamped to zero if the frame overran.

Understanding delta time

dt (delta time) is the number of seconds between the current frame and the previous one. At 60 fps it is approximately 0.0167. Using dt rather than a fixed increment makes animations frame-rate independent:
value += rate * dt
A rate of 10.0f advances value by 10 units per second regardless of whether the frame rate is 30, 60, or 120 fps.

Animating a progress bar

This pattern from the Terminality test application drives a looping progress bar animation entirely from TickEvent:
DispatchTimer::Current().TickEvent += [progress](float dt)
{
    float current = progress->Value.Get();
    current += dt * 10.0f; // advance 10 units per second

    if (current > progress->Maximum.Get())
        current = progress->Minimum.Get(); // wrap back to start

    progress->Value = current;
};
Setting progress->Value marks the widget dirty, causing Terminality to redraw only that control on the next frame. No manual invalidation call is needed.

DispatchTimer vs. OnPropertyChanged

Use caseRecommended mechanism
Continuous animation (position, fill, opacity)DispatchTimer::Current().TickEvent
React to a specific property changingOnPropertyChanged callback on a Property<T>
One-shot deferred actionTickEvent with an unsubscribe after first run
Terminal resize recoveryDispatchTimer::Current().ResizeFinishedEvent
Prefer TickEvent whenever the logic needs to run every frame or accumulate over time. Prefer OnPropertyChanged for reactions that should fire exactly when a value changes and have no concept of elapsed time.
  • RenderContext — draw the animated state inside RenderOverride
  • FocusManager — focus changes fire synchronously, not through TickEvent
  • HostApplicationRunUILoop starts the frame loop that calls Tick()

Build docs developers (and LLMs) love