Overview

mist (https://codeberg.org/periwinkle/mist) is a speedrun timer written in Rust, targeting mainly Linux, but mostly supporting Windows and macOS. It started out as a series of projects that I used to learn Rust, back in 2019 or something. LiveSplit is essentially the industry standard when it comes to speedrun timers, but it only runs on windows, weighs 80MB, and doesn't really behave under wine, so I struck out to Make A Linux Speedrun Timer. Other options were out there but they either didn't work for me or were horribly unmaintained. mist is now effectively feature-complete.

Split files

mist stores information about a speedrun and its associated times in a ron file that looks something like this.

version 2
(
    game_title: "The Legend of Zelda: Breath of the Wild",
    category: "Any%",
    offset: Time(2400),
    pb: None,
    splits: [
        "xeryph",
        "crying skip",
        "magnet man",
        "\'learn new plat\' - mako",
        "old man",
        "wily castle",
        "refights",
        "wily machine",
        "oops wrong game",
    ],
    pb_times: [
        None,
        None,
        None,
        None,
        None,
        None,
        None,
        None,
        None,
    ],
    gold_times: [
        Time(275892),
        Time(240185),
        Time(198240),
        Time(177942),
        Time(130434),
        None,
        None,
        None,
        None,
    ],
    sum_times: [
        (6, Time(1388960)),
        (5, Time(874973)),
        (5, Time(761325)),
        (5, Time(743452)),
        (6, Time(653603)),
        (3, Time(862507)),
        (3, Time(361094)),
        (1, None),
        (1, None),
    ],
)

I think a lot of the elements are fairly self-explanatory but here we go.

TimeType

TimeType is a representation of a time that allows for no time and a skipped split to be represented. The variants are as follows:

Configuration

mist reads its configuration file from the standard location on each operating system, as follows:

A configuration file is also in the ron format, and looks like this. In fact, this is the default config file.

#![enable(implicit_some)]
(
    def_file: None,
    win_size: (300, 500),
    img_file: None,
    img_scaled: false,
    inline_splits: false,
    colors: (
        ahead: (0, 255, 0, 255),
        behind: (255, 0, 0, 255),
        gaining: (255, 90, 90, 255),
        losing: (135, 255, 125, 255),
        gold: (255, 255, 0, 255),
        highlight: (0, 0, 255, 255),
        line: (128, 128, 128, 255),
        background: (0, 0, 0, 0),
        text: (255, 255, 255, 255),
    ),
    frame_rounding: None,
    panels: [],
    t_font: (
        ty: System(
            name: "SansSerif",
            style: Normal,
            weight: Bold,
        ),
        size: 60,
    ),
    s_font: (
        ty: System(
            name: "SansSerif",
            style: Italic,
            weight: Medium,
        ),
        size: 25,
    ),
    ms_ratio: 1.0,
    confirm_exit: true,
    binds: (
        pause: "Return",
        reset: "R",
        start_split: "Space",
        skip_split: "Right Shift",
        un_split: "Backspace",
        prev_comp: "Left",
        next_comp: "Right",
        load_splits: "F1",
        load_config: "F2",
    ),
)

The elements of the file are as follows:

Frame Rounding

Time is, of course, continuous, meaning that a stopwatch or speedrun timer could theoretically display any sub-second value when stopped. However, this may be undesirable, for example in extremely short runs or just ones that require precise timing. Since games have discrete frames, it must take an integer number of frames to complete a run, which means that depending on the framerate of the game, only certain time values are "actually possible". mist supports displaying times compliant with any framerate, as specified by the frame_rounding configuration option. An example of frame rounding at 30 fps is as follows:

Real Time Rounded Time
1.456 1.467
0.633 0.633
3.913 3.933
4.892 4.900

Panels

Panels are used to display additional information about the speedrun in mist. There are three types of panels that can be put into the panels configuration option: SumOfBest, Pace, and CurrentSplitDiff. SumOfBest shows the sum of the runner's golds, theoretically their best possible time. Pace shows a "prediction" for the pace of the run, depending on the current status, such as how far behind or ahead the runner is. CurrentSplitDiff shows how far ahead or behind the runner is currently from the time on the current split that they are comparing against. The latter two are configurable as follows:

Pace( golds: true ),
CurrentSplitDiff( golds: false )

The golds option tells mist whether to compare against pb or against golds when calculating the times to display on these panels.

Fonts

mist can search either for system fonts based on name and style, or use a TTF file from a path. These are specified as follows:

// System font, named Victor Mono, normal weight, italic
System(name: "Victor Mono", style: Italic, weight: Normal)
// Filepath
File(path: "/home/peri/fonts/somefont.ttf")

For system fonts, style can be any of:

weight can be:

mist will do its best to find System fonts, but I am depending on a library for this so if they cannot be found, there isn't much I can do.