Go to file
2026-10-07 22:32:42 +01:00
assets [0.0.0] Capture viewer: a grid of every .mcap's preview, and one capture at full size in a window of its own 2026-10-07 11:41:38 +01:00
modules [0.0.0] OCR on the GPU: measured defaults for memory and batching; scan progress bars 2026-10-07 22:27:29 +01:00
src [0.0.0] Viewer: an OCR button beside the search, as the OCR window only opened itself when CUDA was missing 2026-10-07 22:32:42 +01:00
tools [0.0.0] OCR on the GPU: measured defaults for memory and batching; scan progress bars 2026-10-07 22:27:29 +01:00
.gitignore [0.0.0] OCR: an onnxruntime module and an OCR module, PP-OCRv5 mobile and server, on the GPU through CUDA when it can 2026-10-07 20:45:05 +01:00
check_targets.jai [0.0.0] OCR: an onnxruntime module and an OCR module, PP-OCRv5 mobile and server, on the GPU through CUDA when it can 2026-10-07 20:45:05 +01:00
first.jai [0.0.0] OCR: an onnxruntime module and an OCR module, PP-OCRv5 mobile and server, on the GPU through CUDA when it can 2026-10-07 20:45:05 +01:00
README.md [0.0.0] .mcap version 2: OCR stored in each capture, search, a library scan, sorting by date; turned text 2026-10-07 21:51:18 +01:00

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 .theme files, 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.

The capture viewer

src/app/viewer.jai, catalog.jai and ocr_ui.jai: every .mcap in D:\SnagitIndex\mcap as a grid of previews, and one capture at full size in the Capture window.

  • Search above the grid: every word must match, anywhere in the OCR text, window title, URL, app name or annotation text; "a phrase" matches as one; ocr:, title:, url:, app: and note: limit a word to one field. In the Capture window the matching OCR lines are highlighted, with Next and Previous.
  • Order: newest first by capture date, once the catalog (what search needs from every file) has loaded; by name until then.
  • OCR (modules/OCR): the OCR window shows whether it runs on the GPU and, if not, what to install, and switches model (kept as model under [ocr] in the settings file). Scan the library reads every capture shown that the model has not read yet, storing each reading in its file as it goes, so it can pause, cancel and pick up again. -library FOLDER shows another folder of .mcap files; -scan scans it with the chosen model once it has loaded and exits (0, or 1 if any capture failed), for a scan without the UI, such as on a copy. The Capture window's OCR button reads one capture; a capture read by several models keeps each reading, and the window can show any of them.

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

  1. Name it at the top of first.jai, or let fork.jai do it: APP_NAME (window title, tray, macOS bundle), APP_FOLDER_NAME (executable and data folder; one short lowercase word), APP_BUNDLE_IDENTIFIER and VERSION.
  2. Replace assets/images/icon.png (any square size; it becomes the .exe, .app and window icon) and the tray icons tray_icon.ico (Windows) and tray_icon.png.
  3. Write the app in src/app/app_ui.jai: app_ui_startup runs once, app_ui_frame_start every frame before input, app_main_window_ui draws, and app_ui_shutdown runs 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 by Basic's arenas to wipe memory) is built without libsodium; see the note at the top of modules/Secure_Memory/module.jai if your app keeps secrets in memory.

Uses https://github.com/overlord-systems/jai-imgui as a template.