Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LiveSplit/livesplit-core/llms.txt

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

Timer is the central type in livesplit-core. It wraps a Run and manages all state for a speedrun attempt — tracking the current phase, recording split times, handling game time, and maintaining the attempt history. Every interaction with an active run goes through the Timer.

Construction

Timer::new(run: Run)
Result<Timer, CreationError>
Creates a new Timer from a Run. The Run must have at least one segment; otherwise Err(CreationError::EmptyRun) is returned.
Timer::into_shared(self)
SharedTimer
Converts the Timer into a SharedTimer (Arc<RwLock<Timer>>), allowing it to be shared and controlled across multiple threads. Required for use with HotkeySystem and AutoSplittingRuntime.
Timer::into_run(self, update_splits: bool)
Run
Extracts the underlying Run, resetting any in-progress attempt. If update_splits is true, the current attempt’s data is stored in the Run’s history before returning.
use livesplit_core::{Run, Segment, Timer};

let mut run = Run::new();
run.set_game_name("Super Mario Odyssey");
run.set_category_name("Any%");
run.push_segment(Segment::new("Cap Kingdom"));
run.push_segment(Segment::new("Cascade Kingdom"));

let mut timer = Timer::new(run).expect("Run must have at least one segment");

Timer Controls

All control methods return Result<Event, Error>. An Ok(Event) value describes what changed; an Err(Error) value explains why the command was rejected.
MethodDescription
start()Starts a new attempt. Fails if an attempt is already in progress.
split()Records the current time as the split time. Ends the attempt when the last split is recorded.
split_or_start()Starts a new attempt if not running, or splits if running.
skip_split()Skips the current split. Fails if the current split is the last one.
undo_split()Removes the most recently recorded split time. Switches the phase back to Running if the attempt had ended.
pause()Pauses an active attempt. Fails if already paused.
resume()Resumes a paused attempt. Fails if not paused.
toggle_pause()Toggles between Paused and Running.
toggle_pause_or_start()Toggles pause if running, or starts a new attempt if not running.
undo_all_pauses()Removes all accumulated pause time from the current attempt.
reset(update_splits: bool)Resets the current attempt. If update_splits is true, the attempt is saved to the history.
reset_and_set_attempt_as_pb()Resets and stores the current attempt as the new personal best.
timer.start().unwrap();

// Record splits
timer.split().unwrap();
timer.split().unwrap(); // Last split — attempt ends

// Or reset and try again
timer.reset(true).unwrap(); // save to history

Game Time

Game Time allows tracking a separate timer driven by the game or auto splitter rather than wall-clock time. It must be explicitly initialized for each attempt.
is_game_time_initialized()
bool
Returns true if game time has been initialized for the current attempt.
initialize_game_time()
Result<Event, Error>
Enables game time tracking for the current attempt. Game time is automatically deinitialized when the attempt is reset.
deinitialize_game_time()
Disables game time for the current attempt.
set_game_time(time: TimeSpan)
Result<Event, Error>
Sets the game time to the given value. Works even when game time is paused, which is useful for periodic updates without auto-increment.
loading_times()
TimeSpan
Returns the accumulated loading times. Loading times are defined as Game Time - Real Time.
set_loading_times(time: TimeSpan)
Result<Event, Error>
Sets the loading time offset. The game time is then computed as Real Time - Loading Times automatically.
is_game_time_paused()
bool
Returns true if the game timer is currently paused (not auto-incrementing).
pause_game_time()
Result<Event, Error>
Pauses the game timer so it stops auto-incrementing. Use set_game_time to update it manually.
resume_game_time()
Result<Event, Error>
Resumes the game timer so it auto-increments like real time from its current value.
// Enable game time for this attempt
timer.initialize_game_time().unwrap();

// Option A: Update game time directly (e.g., from game memory)
use livesplit_core::TimeSpan;
timer.set_game_time(TimeSpan::from_seconds(137.5)).unwrap();

// Option B: Track loading times; game time = real time - loads
timer.set_loading_times(TimeSpan::from_seconds(12.0)).unwrap();

State Access

current_phase()
TimerPhase
Returns the current TimerPhase: NotRunning, Running, Paused, or Ended.
current_split_index()
Option<usize>
Returns the index of the segment currently being timed, or None if no attempt is in progress. When the attempt has ended but not been reset, this equals the total segment count.
snapshot()
Snapshot<'_>
Returns a point-in-time snapshot of the timer. All layout rendering should use a snapshot to ensure consistency within a single render frame.
current_timing_method()
TimingMethod
Returns the currently active timing method (RealTime or GameTime).
set_current_timing_method(method: TimingMethod)
Switches the active timing method.
toggle_timing_method()
Toggles between RealTime and GameTime.
current_comparison()
&str
Returns the name of the comparison currently active (e.g. "Personal Best", "Best Segments").
set_current_comparison(comparison: &str)
Result<Event, Error>
Sets the active comparison. Returns Err(ComparisonDoesntExist) if the comparison name is not registered.
switch_to_next_comparison()
Advances to the next comparison in the list.
switch_to_previous_comparison()
Goes back to the previous comparison in the list.
run()
&Run
Accesses the Run currently loaded in the Timer.

Custom Variables

set_custom_variable(name: &str, value: &str)
Sets a custom variable value. If the variable has not been pre-declared in the Run, it becomes a temporary variable that will not be saved to the splits file.
// Set a temporary variable (e.g., from an auto splitter)
timer.set_custom_variable("maps_completed", "3");

Persistence

current_attempt_has_new_best_times()
bool
Returns true if the current attempt has achieved new best times in any segment or a new personal best. Use this to prompt the user whether to save before resetting.
mark_as_unmodified()
Marks the Run as unmodified, indicating all changes have been persisted. Useful after saving to disk.
To serialize the run to a LiveSplit .lss file, use the standalone saver function:
use livesplit_core::run::saver::livesplit::{self, IoWrite};
use std::{fs::File, io::BufWriter};

let file = File::create("run.lss").unwrap();
livesplit::save_run(timer.run(), IoWrite(BufWriter::new(file))).unwrap();
// Or, to include current in-progress attempt data:
livesplit::save_timer(&timer, IoWrite(BufWriter::new(file))).unwrap();

Events and Errors

Most timer control methods return Result<Event, Error>. Event variants — describe what changed:
VariantDescription
StartedA new attempt was started.
SplittedA split was recorded (non-final).
FinishedThe final split was recorded; the run is now ended.
ResetThe attempt was reset.
SplitUndoneThe last split was undone.
SplitSkippedThe current split was skipped.
PausedThe timer was paused.
ResumedThe timer was resumed.
PausesUndoneAll pause times were removed.
PausesUndoneAndResumedAll pause times were removed and the timer was resumed.
ComparisonChangedThe active comparison changed.
TimingMethodChangedThe active timing method changed.
GameTimeInitializedGame time was initialized for this attempt.
GameTimeSetGame time was set to a specific value.
GameTimePausedThe game timer was paused.
GameTimeResumedThe game timer was resumed.
LoadingTimesSetThe loading times offset was set.
CustomVariableSetA custom variable was set.
Error variants — explain rejected commands:
VariantDescription
UnsupportedThe operation is not supported in this context.
BusyThe timer cannot be interacted with at the moment.
RunAlreadyInProgressstart() called when a run is already running.
NoRunInProgressControl called when no attempt is active.
RunFinishedCommand is invalid because the run has already ended.
NegativeTimeCannot split while the timer shows negative time.
CantSkipLastSplitThe last split cannot be skipped.
CantUndoFirstSplitThere is no previous split to undo.
AlreadyPausedpause() called when the timer is already paused.
NotPausedresume() called when the timer is not paused.
ComparisonDoesntExistNamed comparison not found.
GameTimeAlreadyInitializedinitialize_game_time() called when game time is already active.
GameTimeAlreadyPausedpause_game_time() called when game time is already paused.
GameTimeNotPausedresume_game_time() called when game time is not paused.
CouldNotParseTimeA time string could not be parsed.
TimerPausedThe command is invalid because the timer is paused.
RunnerDecidedAgainstResetThe runner chose not to reset when prompted.

Build docs developers (and LLMs) love