OpenSpeedRun is a modern and minimalistic open-source speedrun timer designed for Unix systems. It features a clean GUI, external CLI control, and customizable themes.
![]() |
![]() |
|---|
- β¨ Lightweight and responsive GUI
- πΌοΈ Theme customization (colors, font sizes, and visibility toggles)
- π§© Split editor with support for icons and pagination
- π§ Config editor for managing themes and splits
- π₯οΈ CLI interface for external control
- π¦ No dependencies on non-Unix libraries
OpenSpeedRun provides 3 executables:
openspeedrun: the main GUI speedrun timeropenspeedrun-cli: a command-line tool to control the timer externally (e.g., split, reset, pause), available only for Unix.openspeedrun-cfg: configuration GUI to manage themes and splits
Precompiled binaries are available for Windows, Linux, and macOS in the Releases section.
- Go to the Releases page.
- Download the
.zipfor Windows (e.g.openspeedrun-windows-x86_64.zip). - Extract it anywhere (e.g.
C:\Games\OpenSpeedRun\). - Run
openspeedrun.exe.
β You can also run
openspeedrun-cfg.exefor configuration.
- Download the
.zipfor Linux (e.g.openspeedrun-linux-gnu-x86_64.zip). - Extract it:
unzip openspeedrun-linux-gnu-x86_64.zip
- Move the binaries to somewhere in your PATH, or run from current directory:
./openspeedrun
π‘ You may need to make the binaries executable:
chmod +x openspeedrun openspeedrun-cfg openspeedrun-cli
You can also install it on ArchLinux-based distributions from AUR
β οΈ Currently untested on macOS. You can try the following steps:
- Download the macOS zip file (e.g.
openspeedrun-macos-x86_64.zip). - Extract it:
unzip openspeedrun-darwin-x86_64.zip
- Run from terminal:
./openspeedrun
π‘οΈ If you get a βcannot be opened because it is from an unidentified developerβ error, try:
chmod +x openspeedrun xattr -d com.apple.quarantine openspeedrun
Build with Cargo:
cargo build --releaseOr install directly:
cargo install --path .To start the timer:
openspeedrunTo configure splits and themes:
openspeedrun-cfgopenspeedrun includes a companion binary: openspeedrun-cli, designed for both Wayland and X11 environments.
Since many Wayland compositors do not support global hotkeys, and even on X11 you may prefer custom shortcuts, openspeedrun-cli allows you to control the timer externally.
You can bind system-wide keyboard shortcuts in your window manager or compositor to commands like:
openspeedrun-cli splitThis enables full control (start, pause, reset, split) without relying on the GUI, ensuring compatibility and flexibility in any environment.
On Windows, OpenSpeedRun supports customizable hotkeys.
You can assign your own keys for actions like start, split, and reset using the openspeedrun-cfg configuration tool.
- Start/Stop:
F1 - Split:
F2 - Reset:
F3
OpenSpeedRun supports custom fonts for a personalized look.
You can add fonts in two ways:
- Manually place a
.ttfor.otffile inside the following folder, depending on your OS:- On Linux/macOS/BSD:
~/.config/openspeedrun/fonts/ - On Windows:
"%APPDATA%\openspeedrun\fonts\"
- On Linux/macOS/BSD:
- Or, use the graphical configuration tool (
openspeedrun-cfg) and click on "Load Font". This will open a file picker, copy the selected font file into the samefonts/directory, and let you choose from any installed font there.
β οΈ Recommended: Use a monospaced font (e.g., Roboto Mono, JetBrains Mono, or Courier New).
Non-monospaced fonts may cause jittery or uneven digit movement in the timer display as numbers change.
For shaders used as backgrounds in this app, follow these conventions to ensure compatibility and expected behavior.
Supported versions are: 1.10, 1.20, 1.30, 1.40, 1.50, 3.30, 4.00, 4.10, 4.20, 4.30, 4.40, 4.50, 4.60, 1.00 ES, 3.00 ES, 3.10 ES, and 3.20 ES
- You must explicitly declare a #version directive β e.g., #version 100 (minimum supported version).
- Use GLSL ES 1.00 or higher.
- Define an attribute named
a_posof typevec2. - Compute
gl_Positionfroma_pos. - No additional outputs are required unless your fragment shader needs them.
π‘ You may use higher versions like
#version 330 corewhen running in desktop OpenGL contexts. This allows for more modern syntax (in,out,layout, etc.) and features.
#version 100
attribute vec2 a_pos;
void main() {
gl_Position = vec4(a_pos, 0.0, 1.0);
}#version 330 core
in vec2 a_pos;
out vec2 v_uv;
void main() {
v_uv = (a_pos + 1.0) * 0.5;
gl_Position = vec4(a_pos, 0.0, 1.0);
}- You must explicitly declare a #version directive β e.g., #version 100 (minimum supported version).
- Use GLSL ES 1.00 or higher.
- Use
gl_FragCoordor interpolated UVs to compute per-pixel output.
ποΈ In GLSL 1.00, write to
gl_FragColor.
π¨ In modern GLSL (#version 330 core), define anout vec4likeFragColor.
Uniforms:
| Alias(es) | Description |
|---|---|
u_time, time, iTime |
Elapsed time in seconds |
u_resolution, resolution, iResolution |
Viewport size in pixels |
u_mouse, mouse, iMouse |
Is always (0, 0) |
deltaTime, u_deltaTime, iTimeDelta |
Time elapsed between frames in seconds |
u_date, date, iDate |
Current date: (year, month, day, seconds) |
u_texture, iChannel0, image |
Background texture (optional) |
u_current_split, current_split, iCurrentSplit |
Current split index (0-based) |
u_total_splits, total_splits, iTotalSplits |
Total number of splits |
u_elapsed_time, elapsed_time, iElapsedTime |
Total elapsed time in seconds |
u_elapsed_split_time, elapsed_split_time, iElapsedSplitTime |
Time since last split in seconds |
#version 100
precision mediump float;
uniform float u_time;
uniform vec2 u_resolution;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
gl_FragColor = vec4(uv, abs(sin(u_time)), 1.0);
}#version 330 core
in vec2 v_uv;
out vec4 FragColor;
uniform float u_time;
uniform vec2 u_resolution;
float wave(vec2 uv, float speed, float freq, float amp) {
return sin((uv.x + u_time * speed) * freq) * amp +
cos((uv.y + u_time * speed * 0.8) * freq * 0.7) * amp * 0.5;
}
void main() {
vec2 uv = v_uv;
float distortion = wave(uv, 0.4, 8.0, 0.02);
vec2 distorted_uv = uv + vec2(distortion);
float depth = 0.5 + 0.5 * sin(10.0 * distorted_uv.x + u_time)
* cos(10.0 * distorted_uv.y + u_time);
vec3 water_color = mix(vec3(0.0, 0.2, 0.4), vec3(0.0, 0.6, 1.0), depth);
float specular = pow(max(0.0, depth), 3.0);
water_color += specular;
FragColor = vec4(water_color, 1.0);
}for examples of shaders, see the shaders directory.
![]() |
![]() |
![]() |
|---|
OpenSpeedrun is currently under active development and fully usable.
Released under the BSD 3-Clause License, the software is free to use, modify, and redistribute, with or without contributions back to the original project.
Made with β€οΈ for the speedrunning community.




