Lagrange is a versatile client for browsing Geminispace. It offers modern conveniences familiar from web browsers, such as smooth scrolling, inline image viewing, multiple tabs, visual themes, Unicode fonts, bookmarks, history, and page outlines.
Lagrange is designed to be platform-independent. It relies on a small number of essential libraries for complex features like text rendering and cryptography. It is written in C and uses SDL 3 for hardware-accelerated graphics and OpenSSL for secure communications.
- Beautiful typography with full Unicode support
- Autogenerated page style and symbol for each Gemini domain
- Scrolling and paginated view modes
- Smart suggestions when typing the URL — search bookmarks, history, identities
- Sidebars for page outline, managing bookmarks, viewing history, and other features
- Identity management — create and use TLS client certificates
- Audio playback: built-in MP3, Ogg Vorbis, WAV support
- Sync user data across devices
- Gempub books
- Curses-based TUI as an alternative to the graphical interface
- And much more! Open
about:helpin the app, or see help.gmi
Prebuilt binaries for Windows, macOS (10.13 or later) and Linux can be found in Releases. You can also find Lagrange on Flathub for Linux.
On macOS you can install and upgrade via Homebrew:
brew install --cask lagrange
Please check MacPorts if you are using macOS 10.12 or older.
On Fedora and any RHEL/CentOS Stream 8 and 9 derivatives (RHEL, CentOS Stream, Alma, Rocky) that have the EPEL repos enabled:
sudo dnf install lagrange
On openSUSE Tumbleweed:
sudo zypper install lagrange
Using GNU Guix:
guix install lagrange
You need a POSIX-compatible environment to compile Lagrange, or on Windows, either MSYS2 or Visual Studio with vcpkg (see Compiling on Windows).
The required tools are a C11 compiler (e.g., Clang or GCC), CMake (3.15 or newer), pkg-config, and zip. Additional tools are required if GNU FriBidi or HarfBuzz are compiled as part of the build (see Unicode text rendering).
- Download and extract a source tarball from Releases.
- Note: GitHub/Gitea-generated tarballs do not contain the_Foundation, HarfBuzz, GNU FriBidi, or SEALCurses submodules; check which tarball you are downloading.
- Alternatively, you may also clone the repository and its submodules:
git clone --recursive --branch release https://git.skyjake.fi/gemini/lagrange
- Check that you have the build tools and dependencies installed: SDL 3, OpenSSL (1.1.1 or newer), PCRE2 (or the older libpcre), libunistring, and zlib. On Windows (MSYS2/MinGW) and Linux/Unix, you may also want FreeType, HarfBuzz, and GNU FriBidi (for high-fidelity text rendering), and on Linux/Unix, Fontconfig (for locating system fonts). For example,
- on macOS using Homebrew:
brew install cmake pkgconf sdl3 openssl@3 pcre2 libunistring - on Ubuntu (25.04 or newer) or Debian (13 or newer):
sudo apt install cmake zip libsdl3-dev libssl-dev libpcre2-dev zlib1g-dev libunistring-dev libfreetype-dev libharfbuzz-dev libfribidi-dev libfontconfig-dev - on Fedora:
sudo dnf install cmake zip SDL3-devel openssl-devel pcre2-devel zlib-devel libunistring-devel freetype-devel harfbuzz-devel fribidi-devel fontconfig-devel
- on macOS using Homebrew:
- Optionally, install additional libraries for audio and image formats. These are detected automatically with
pkg-config:- mpg123 for MPEG audio (Homebrew:
mpg123, Ubuntu:libmpg123-dev, Fedora:mpg123-devel) - opusfile for Opus audio (Homebrew:
opusfile, Ubuntu:libopusfile-dev, Fedora:opusfile-devel) - libwebp for WebP images (Homebrew:
webp, Ubuntu:libwebp-dev, Fedora:libwebp-devel) - libjxl for JPEG XL images (Homebrew:
jpeg-xl, Ubuntu:libjxl-dev, Fedora:libjxl-devel)
- mpg123 for MPEG audio (Homebrew:
- Configure the build in a new build directory:
cmake -S {path_of_lagrange_sources} -B build -DCMAKE_BUILD_TYPE=Release - Build it:
cmake --build build - Now you can run
build/app/lagrange,build\app\lagrange.exe, orbuild/app/Lagrange.app.
If SDL 3 is not found, the GUI app is not built. CMake prints a summary of the enabled options at the end of the configuration.
Lagrange uses the platform's native text rendering when available:
- On macOS and iOS, Core Text is used for loading fonts and for shaping and rendering text (
ENABLE_CORETEXT). No other text rendering libraries are needed. - On Windows and Linux/Unix, glyphs are rendered with FreeType (
ENABLE_FREETYPE). Text is shaped with HarfBuzz, and GNU FriBidi handles bidirectional text. The system-provided HarfBuzz is always used together with FreeType, because the two libraries are built to work with each other.
GNU FriBidi is located with pkg-config. If it is not found, it is compiled from the lib/fribidi submodule as part of the build. Set ENABLE_FRIBIDI_BUILD to ON to always use the submodule. Note that GNU FriBidi cannot be compiled with CMake; you need to have Meson and Ninja.
If both Core Text and FreeType are disabled, a simpler built-in font renderer (stb_truetype) is used instead. It does not support system fonts, color Emoji, or font hinting. In this configuration, HarfBuzz is located with pkg-config, or compiled from the lib/harfbuzz submodule if not found (or if ENABLE_HARFBUZZ_MINIMAL is set to ON). Compiling HarfBuzz requires a C++ compiler, and preferably Meson and Ninja.
You may also disable FreeType, HarfBuzz, and GNU FriBidi entirely. A simplified text shaping algorithm is then used that only supports non-complex left-to-right scripts.
By default, the compiled app will be installed to a system-wide location determined by CMake.
Set CMAKE_INSTALL_PREFIX to install to a directory of your choosing:
cmake -S {path_of_lagrange_sources} -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/dest/pathcmake --build build --target install
On Linux/Unix, the install target also deploys an XDG .desktop file for launching the app, an icon, AppStream metadata, and the lagrange.1 manual page.
| CMake Option | Default | Description |
|---|---|---|
ENABLE_APP_BUNDLE |
ON | Build a macOS app bundle (Lagrange.app). If set to OFF, the app is installed Unix-style, with the executable and resources in separate directories. (Only on macOS.) |
ENABLE_CORETEXT |
ON | Use Core Text for loading fonts and for shaping and rendering text. This provides access to system fonts and color Emoji. Replaces HarfBuzz and GNU FriBidi. Cannot be used together with ENABLE_FREETYPE. (Only on macOS and iOS.) |
ENABLE_CUSTOM_FRAME |
OFF | Draw a custom window frame. (Only on Microsoft Windows.) The custom frame is more in line with the visual style of the rest of the UI, but does not implement all of the native window behaviors (e.g., snapping, system menu). |
ENABLE_DOWNLOAD_EDIT |
ON | Allow changing the Downloads directory via the Preferences dialog. This should be set to OFF in sandboxed environments where downloaded files must be saved into a specific place. |
ENABLE_FRAME_TIMING |
OFF | Print statistics about frame timing. Useful for debugging rendering performance. |
ENABLE_FREETYPE |
ON (Apple: OFF) | Use the FreeType library for loading fonts and rendering glyphs. This provides access to system fonts and color Emoji. Requires the system-provided HarfBuzz. |
ENABLE_FRIBIDI |
ON | Use the GNU FriBidi library for processing bidirectional text. FriBidi implements the Unicode Bidirectional Algorithm to determine text directions. |
ENABLE_FRIBIDI_BUILD |
OFF | Compile the GNU FriBidi library from the lib/fribidi submodule. If set to OFF, pkg-config is used to locate the library, falling back to the submodule if it is not found. |
ENABLE_GAMEPAD |
ON | Allow gamepad UI input. |
ENABLE_GUI |
ON | Build the GUI application. Requires SDL 3. |
ENABLE_HARFBUZZ |
ON | Use the HarfBuzz library for shaping Unicode text. This is required for correctly rendering complex scripts and combining glyphs. If disabled, a simplified text shaping algorithm is used that only works for non-complex languages like English. (Not used with Core Text.) |
ENABLE_HARFBUZZ_MINIMAL |
OFF | Compile the HarfBuzz library from the lib/harfbuzz submodule with all dependencies disabled. Useful when building the app for distribution so that the number of deployed dependencies will be minimized. If set to OFF, pkg-config is used to locate the library, falling back to the submodule if it is not found. (Not used with FreeType or Core Text.) |
ENABLE_IDLE_SLEEP |
OFF | Sleep in the main thread instead of waiting for events. On some platforms, SDL_WaitEvent() may have a relatively high CPU usage. Setting this to ON polls for events periodically but otherwise keeps the main thread sleeping, reducing CPU usage. The drawback is that there is a slightly increased latency reacting to new events after idle mode ends. |
ENABLE_IPC |
ON | Instances of the Lagrange executable communicate via signals or (on Windows) a system-provided IPC mechanism. This is used for controlling an existing Lagrange window via the CLI. If set to OFF, each instance of the app runs without knowledge of other instances. This may cause them to overwrite each other's runtime files. |
ENABLE_JXL |
ON | Use libjxl to decode .jxl images, if pkg-config can find the library. |
ENABLE_KERNING |
ON | Use kerning information in the fonts to adjust glyph placement. Setting this ON improves text appearance in subtle ways but slows down text rendering. It may be a good idea to set this to OFF when running on a slow CPU. This option only affects the simple built-in text renderer, and has no effect on HarfBuzz, FreeType, or Core Text. |
ENABLE_MAC_MENUS |
ON | Use native context menus on macOS. |
ENABLE_MOBILE_HANDHELD |
OFF | Use the mobile handheld UI variant. Assumes that a gamepad is used for controlling the app, ENABLE_GAMEPAD should also be set. It is suitable for handheld game consoles, for instance. |
ENABLE_MOBILE_PHONE |
OFF | Use the mobile phone UI variant. This replaces the sidebars with a sliding sheet and has other touch-friendly features. Settings and dialogs are presented as form-based sheets. |
ENABLE_MOBILE_TABLET |
OFF | Use the tablet UI variant. Sidebars are available as on the desktop, but Settings and dialogs are presented as form-based sheets. |
ENABLE_MPG123 |
ON | Use the mpg123 library for decoding MPEG audio files. |
ENABLE_OPUS |
ON | Use the opusfile library for decoding Opus audio files. |
ENABLE_POPUP_MENUS |
ON | Use popup windows for context menus. If OFF, menus are confined inside the main window. |
ENABLE_RELATIVE_EMBED |
OFF | Locate resources only in relation to the executable. Useful when any system/predefined directories are not supposed to be accessed, e.g., in the Windows portable build. |
ENABLE_RESIZE_DRAW |
ON (Haiku and Android: OFF) | Force the window to redraw while being resized. May be necessary on some platforms. |
ENABLE_SPARKLE |
OFF | Use the Sparkle framework for automatic updates. (macOS only) |
ENABLE_STATIC |
OFF | Link dependencies statically. |
ENABLE_TUI |
OFF | Build the TUI application (clagrange). The SEALCurses library is required (it replaces SDL); check that the lib/sealcurses submodule is checked out. |
ENABLE_WEBP |
ON | Use libwebp to decode .webp images, if pkg-config can find the library. |
ENABLE_WINDOWPOS_FIX |
OFF | Set correct window position after the window has already been shown. This may be necessary on some platforms to prevent the window from being restored to the wrong position. |
ENABLE_WINSPARKLE |
OFF | Use WinSparkle for automatic updates. (Windows only) |
ENABLE_X11_SWRENDER |
OFF | Default to software rendering when running under X11. By default Lagrange attempts to use the GPU for rendering the user interface. You can also use the --sw option at launch to force software rendering. |
ENABLE_X11_XLIB |
ON | Use the Xlib API directly under X11. This is used for window decoration color theming, for example. |
Additional CMake cache variables:
| Variable | Description |
|---|---|
CACERT_PEM_PATH |
Path of a root CA certificate bundle (cacert.pem) to include as a built-in resource. |
RESOURCES_LGR_PATH |
Additional location to check when searching for the "resources.lgr" file at launch. |
Lagrange also supports a text user interface (TUI) that allows running the app in a terminal. The GUI and TUI are built as separate executables. By default, the TUI is disabled in the build settings. Set the ENABLE_TUI option to YES to build the TUI executable (clagrange). If the GUI is not needed, you can disable it by setting ENABLE_GUI to NO.
In the TUI build, SDL is replaced with a library called SEALCurses that implements a subset of the SDL API on top of Curses. The requirements for building the TUI are otherwise the same as with the GUI, except FreeType, HarfBuzz, FriBidi, and all the image and audio dependencies will not be used.
The source tree also contains two command line tools:
lgrsyncdis the sync server for Lagrange's user data sync. It only depends on the_Foundation. When the app is being built,lgrsyncdis excluded from the default build target; build it withcmake --build build --target lgrsyncd. Alternatively, configure the "sync" subdirectory as a separate project:cmake -S sync -B build-sync && cmake --build build-sync.gmgetis a simple curl-like tool for making Gemini requests on the command line using Lagrange's identities and user data. It is built from the "lib/core" directory and installed next to the app executable, unless theINSTALL_GMGEToption is set toNO.
See the Technical Reference (about:reference in the app) for usage instructions.
When using OpenSSL from Homebrew, you must add its pkgconfig path to your PKG_CONFIG_PATH environment variable, for example:
export PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig
By default, the build produces an app bundle (Lagrange.app) with SDL embedded inside it. Set ENABLE_APP_BUNDLE to OFF for a Unix-style build that can be installed under a prefix like any other command line program.
There are two ways to compile Lagrange on Windows: natively with Visual Studio and vcpkg, or using MSYS2.
The required dependencies are listed in the vcpkg manifest file (vcpkg.json), so vcpkg installs them automatically during CMake configuration. CMake 3.21 or newer is required for installing the app.
- Install the Build Tools for Visual Studio 2022 with the "Desktop development with C++" component.
- Install vcpkg and set the
VCPKG_ROOTenvironment variable to point to it. - Configure using the "vcpkg" preset in your source directory:
cmake --preset vcpkg - Build it:
cmake --build build --config Release - Optionally, install to a directory of your choosing. This also deploys the needed DLLs:
cmake --install build --config Release --prefix C:\dest\path
You should use a version of the SDL 3 library that is compiled for native Windows (i.e., the MSVC variant) instead of the version from MSYS2 or MinGW. You can download a copy of the SDL binaries from libsdl.org. To make configuration easier in your MSYS2 environment, consider writing a custom sdl3.pc file so pkg-config can automatically find the correct version of SDL. Below is an example of what your sdl3.pc might look like:
prefix=/c/SDK/SDL3-3.2.0/
arch=x64
libdir=${prefix}/lib/${arch}/
incdir=${prefix}/include/
Name: sdl3
Description: Simple DirectMedia Layer
Version: 3.2.0-msvc
Libs: ${libdir}/SDL3.dll -mwindows
Cflags: -I${incdir}
The -mwindows option is particularly important as that specifies the target is a GUI application. Also note that you are linking directly against the Windows DLL — do not use any prebuilt .lib files if available, as those as specific to MSVC.
pkg-config will find your .pc file if it is on PKG_CONFIG_PATH or you place it in a system-wide pkgconfig directory.
Once you have compiled a working binary under MSYS2, there is still an additional step required to allow running it directly from the Windows shell: the shared libraries from MSYS2 must be found either via PATH or by copying them to the same directory where lagrange.exe is located.
On Raspberry Pi 4/400 and newer, you can compile and run Lagrange just like on a regular desktop PC. Accelerated OpenGL graphics should work fine under X11.
On Raspberry Pi 3 or earlier, you should use a version of SDL that is compiled to take advantage of the Broadcom VideoCore OpenGL ES hardware. This provides the best performance when running Lagrange in a console. OpenGL under X11 on Raspberry Pi 2/3 is quite slow/experimental. When running under X11, software rendering is the best choice and the SDL from, say, Raspberry Pi OS is sufficient.
The following build options are recommended on Raspberry Pi 2/3:
ENABLE_WINDOWPOS_FIX=YES: workaround for window position restore issues (SDL bug)ENABLE_X11_SWRENDER=YES: use software rendering under X11
You will need Xcode and CMake. The dependencies are compiled separately for the device and the simulator (arm64 only). HarfBuzz and GNU FriBidi are not needed because text is rendered with Core Text.
- Get the dependency sources. platform/ios-deps.sh expects to find libiconv, libunistring, pcre-8.44, libwebp, libjxl (with its submodules), and SDL 3 in $HOME/src/libs/ (set
IOS_SRCto use another directory), and the_Foundation in $HOME/src/the_Foundation/ (TFDN_SRC). OpenSSL 3 is downloaded automatically. The Autotools-based sources must have a configure script. - Run
platform/ios-deps.sh osfor the device orplatform/ios-deps.sh simulatorfor the simulator. The libraries are installed in $HOME/SDK/ios/arm64/ or $HOME/SDK/ios-sim/arm64/, respectively. To rebuild only some of the dependencies, list the steps after the target, for example:platform/ios-deps.sh os foundation. - In an empty build directory, run
platform/cmake-ios-lagrange.sh os -DXCODE_DEVELOPMENT_TEAM=<team ID>orplatform/cmake-ios-lagrange.sh simulatorto generate an Xcode project that builds the app. Additional CMake options can be appended to the command.
Lagrange can be compiled to WebAssembly with Emscripten and run in a web browser. You will need the Emscripten SDK, CMake, Ninja, and Meson (for HarfBuzz and FriBidi, which are built from the lib/ submodules).
- Activate the Emscripten environment:
source /path/to/emsdk/emsdk_env.sh - Run platform/wasm-deps.sh to download and compile the dependencies. They are installed in $HOME/SDK/wasm/ by default; give a different prefix as an argument if needed, and set
WASM_DIRto match when building the app. - Run platform/wasm-site.sh to build the desktop, phone, and tablet variants of the app and assemble them into a static site under build-web/site/.
Alternatively, a single variant can be configured manually with emcmake cmake -S . -B build-web -G Ninja and built with cmake --build build-web. The output files are in build-web/app/.
The app uses threads, so the web server must send the Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers for the page to be cross-origin isolated. Browsers cannot open direct connections to Gemini servers, so network traffic goes through a WebSocket relay; see lagrange-relay for the server.
One instance of Lagrange can be running at a time per user directory.
On Windows, user files are stored in %HOMEPATH%/AppData/Roaming/fi.skyjake.Lagrange/, unless one is using the portable distribution and there is a userdata/ subdirectory present in the executable directory.
On macOS, user files are stored in ~/Library/Application Support/fi.skyjake.Lagrange/.
On Linux/*BSD/other operating systems, user files are stored in ~/.config/lagrange/ unless you have customized the XDG directories, in which case the XDG_CONFIG_HOME environment variable is used to determine where user files are saved.
The usage and contents of the user files are described in the Technical Reference (about:reference in the app). You can delete one or more of the files while Lagrange is not running to reset the corresponding data to the default/empty state.
