| assets | ||
| modules | ||
| src | ||
| tools | ||
| .gitignore | ||
| check_targets.jai | ||
| first.jai | ||
| README.md | ||
mcap
A bare Dear ImGui (docking branch) desktop application
written in Jai, for Windows, macOS and Linux: the window, the frame loop
and everything around them, ready for an app to be written into src/app/app_ui.jai.
What you get
- Native rendering per platform. Win32 + Direct3D 11 on Windows; SDL3 + SDL_GPU (Metal on macOS, Vulkan on Linux) elsewhere. On Windows the window comes up on a WARP device in a few milliseconds while the hardware device is created on a thread, then moves across; a lost device is recovered.
- Docking and multi-viewport ImGui, with a default layout (
assets/data/default_imgui.ini) and a Reset Layout hotkey. - One instance. Launching the app again brings the running one forward, over a shared memory channel (a file lock decides the owner on macOS and Linux).
- Tray / menu bar. Closing or minimizing hides the window to the tray; the tray icon brings it back or quits.
- Hotkeys from a
[hotkeys]section of the settings file, and global hotkeys ([global_hotkeys]: Windows and macOS) that work while another app is in front. - A settings file (
settings.config) that is written with every key listed, reloaded as soon as it is saved, and merged rather than overwritten when the app saves to it. - Themes: built-ins, 36 shipped
.themefiles, and a theme editor that saves new ones. - Logging through a multi-producer, single-consumer queue to a per-version log file and an in-app Event Log, plus crash reports.
- Debug panels: frame times, memory, renderer, fonts (Ctrl+Shift+D, Ctrl+Shift+1).
- DPI awareness, live resize that keeps drawing, CJK font fallback from the system fonts.
- Background shutdown: closing hands the remaining work to a thread while the window shows progress, so it never looks hung.
- Asynchronous tests, compiled into debug builds and run with
run_tests.
Building
Requires the Jai compiler, beta 0.2.030 or later.
jai first.jai # debug build
jai first.jai - release # release build
jai first.jai - full_release # debug and release
jai first.jai - release compile_tests # release build with the test suite
Binaries are written to bin/, with assets/ copied beside them.
| Platform | Output | Notes |
|---|---|---|
| Windows | bin/mcap-debug.exe, bin/mcap.exe |
The release build gets the icon and a manifest, and no console. |
| macOS | bin/mcap-macos-debug, bin/mcap.app |
Apple silicon (arm64) only, with a native jai. The release build is an ad hoc signed .app. |
| Linux | bin/mcap-linux-debug, bin/mcap-linux |
Needs SDL3 installed (libSDL3.so). |
jai check_targets.jai - linux type-checks the Linux build from any OS without linking it.
The macOS check only works on a Mac, since the Objective-C module runs code at compile time.
Run any build with run_tests to run the test suites (debug builds include them),
-allow-multiple-instances to skip the single-instance check, or -version.
For unattended runs (scripts, CI, agents), add -headless: the app exits once the tests finish,
with exit code 0 if every suite passed and 1 otherwise, and a failed assertion or runtime check
is written to stderr, the log and the crash report and exits with 1 instead of opening a message
box (runtime_support_headless in modules/Runtime_Support.jai):
bin/mcap-debug.exe run_tests -headless -allow-multiple-instances > test-output.txt
jai first.jai - no_crash_dialog [...] makes builds for automation: NO_CRASH_DIALOG makes them
headless whatever their arguments, and everything they build goes to bin-headless/ instead of
bin/, so an automated build never writes over the one you run by hand.
Starting a new app
jai fork.jai - <output_directory> <app_name> [-folder <name>] [-bundle-id <id>] [-version <x.y.z>] [-git] [-build]
jai fork.jai - ../my-cool-app "My Cool App" -git -build
This copies the template (without bin/, .build/, .git/ or fork.jai) and sets the names
below in the copy. The folder name defaults to the app name in lowercase with spaces as -
(my-cool-app), the bundle identifier to com.example.<folder without dashes>, and the version
to 0.0.0. -git initializes a repository and commits the copy; -build makes a debug build. It also
writes <app_name>.focus-config, a focus project with the build and
run commands, which stays out of git since it holds this machine's paths.
Making it your app
- Name it at the top of
first.jai, or letfork.jaido it:APP_NAME(window title, tray, macOS bundle),APP_FOLDER_NAME(executable and data folder; one short lowercase word),APP_BUNDLE_IDENTIFIERandVERSION. - Replace
assets/images/icon.png(any square size; it becomes the.exe,.appand window icon) and the tray iconstray_icon.ico(Windows) andtray_icon.png. - Write the app in
src/app/app_ui.jai:app_ui_startupruns once,app_ui_frame_startevery frame before input,app_main_window_uidraws, andapp_ui_shutdownruns on the shutdown thread.
To add a hotkey, declare a Hotkey in src/ui/imgui_keyboard.jai, add it to
hotkey_actions_build and app_check_key_combinations, bind it in both
assets/data/default_hotkeys*.config files (the build fails if a default leaves an action
unbound), and raise APP_USER_SETTINGS_VERSION in src/App.jai so existing settings files get
the new default.
To add a setting, add it to App_User_Settings, Settings_Seen, settings_parse and
app_save_user_settings_file in src/ui/imgui_theme_registry.jai.
Layout
first.jai build: workspaces, build constants, Windows icon/manifest, macOS .app
fork.jai copy the template to a new, named project
check_targets.jai type-check another OS's build
src/App.jai loads everything; global state (app, platform, perf)
src/app/ main loop, your UI, background shutdown
src/base/ logging, fonts, debug panels, platform layers (base/platform/)
src/ui/ ImGui setup, hotkeys, themes and settings, toasts
src/graphics/DX11.jai Direct3D 11 device, WARP-first startup, device-loss recovery
src/backends/ ImGui's SDL_GPU backend; src/freetype/: ImGui's FreeType loader
assets/ fonts, icons, default hotkeys, default layout, themes
modules/ Basic (with arenas), Thread, Shared_Memory_Channel, File_Watcher,
Secure_Memory, XDG, sdl3, imgui-sdl, imgui-dx11-win32, imgui-source
Files at run time
| File | Location |
|---|---|
settings.config, imgui.ini, user themes |
%APPDATA%\<APP_FOLDER_NAME> on Windows, ~/Library/Application Support/<APP_FOLDER_NAME> on macOS, ~/.local/share/<APP_FOLDER_NAME> on Linux |
| Logs | logs/<version>/ next to the executable (next to the .app on macOS) |
| Shipped themes | data/themes/ next to the executable |
Platform notes
- Global hotkeys are not implemented on Linux (Wayland has no API for them). A desktop shortcut that launches the executable has the same effect, since a second launch brings the running instance forward.
- On XFCE the tray icon stays after the window is restored.
Secure_Memory(used byBasic's arenas to wipe memory) is built without libsodium; see the note at the top ofmodules/Secure_Memory/module.jaiif your app keeps secrets in memory.
Uses https://github.com/overlord-systems/jai-imgui as a template.