Kryon is a small C support library for raylib-style applications. It keeps a
raylib-compatible public surface available through kryon.h, then adds the
pieces shared by downstream apps: UI controls, Tk-style toolkit widgets, layout
helpers, text rendering, themes, embedded assets, locale loading, file dialogs,
desktop tray support, runtime asset downloads, and optional account/sync helpers.
include/- public headers, includingkryon.hand generated raylib compatibility declarationssrc/- Kryon implementation files, with reusable UI modules undersrc/ui/icons/- MingCute UI and full-color spritesheets embedded bysrc/ui/ui_icon_assets.cthemes/- built-in theme files for the runtime theme loaderfonts/noto/- bundled Noto Sans TTF/OTF font assetsmk/- Make fragments for native, web, Android, Windows, packaging, and vendored dependency buildsscripts/- asset embedding, icon embedding, raylib preparation, and boundary check helpersexamples/- small programs that exercise Kryon UI featurestests/- focused C tests for account, sync, and transition helpersvendor/raylib,vendor/curl,vendor/liboqs- source submodules used by downstream app builds
Kryon builds with the repository Makefile:
makeRun the focused tests with:
make testBackend selection is link-time via KRYON_BACKEND. Supported backends are:
raylib- the default desktop, Android, Windows, and WebGL path, with SDL2/OpenGL integration in the build rules.canvas- the HTML5 Canvas2D/WebAudio backend for Emscripten web builds.dom- the browser DOM/CSS backend for web UI surfaces.libdraw- the plan9port libdraw/devdraw backend.termi- the terminal-cell backend.null- generated no-op stubs for headless tests and unsupported surface areas.
Build a distributable static-library archive with:
make dist-staticThe archive is an extracted SDK layout. It contains libkryon.a,
libraylib.a, vendored static dependency libraries, public headers, API docs,
example consumers, CMake and pkg-config metadata, third-party notices, a package
manifest, and the submodule revisions used to build it. Validate it with:
make check-static-packageRun the full release readiness gate with:
make release-preflightlibkryon.a stays focused on Kryon object files. Companion libraries are shipped
beside it and linked through lib/pkgconfig/kryon.pc. OpenSSL is still treated
as an external system/toolchain dependency unless explicit OpenSSL static library
paths are supplied at build time.
Every successful CI run on master automatically advances the patch version,
commits include/kryon_version.h, and starts the tag-driven Release workflow.
The workflow validates the version, creates an annotated tag, builds and tests
Kryon, and publishes both the static SDK and a checksummed native tools bundle.
The tools bundle contains k2c, k2cpp, k2go, k2js, k2kir, k2b, kt, kryon,
kryon-preview, krb-run, and krb-sdl. The renderer workflow also attaches
the Linux, Windows, and macOS krb-run builds plus the web player to the same
release.
Maintainers can still run Release manually for the checked-in version. Use
scripts/bump-version.sh minor / major before pushing when a non-patch bump is
required. Pushing a matching v* tag manually uses the same build-and-publish
path; releases reject tags that disagree with the public version header.
To integrate Kryon into your project:
- Add
include/to your header search paths - Include
kryon.hfor the raylib-compatible API plus Kryon modules - Compile Kryon sources from
src/andsrc/ui/, or use themk/fragments to let Kryon assemble source lists and platform flags - Kryon's checked-in
icons/tree is the source of truth for the finished MingCute Core UI sheet, a separate full-color logo sheet, and the full-color platform, payment, language, tile, and profile sheets.make icons-embedrefreshes the embedded C assets from those sheets. UseDrawIconor the generatedIconwidget with a runtimeColor; no per-color files or per-icon textures are needed. Downstream apps can callvendor/kryon/scripts/sync-icons.shto copy the sheets. Maintainers can refresh the UI subset from an upstream checkout withmake icons-import-mingcute MINGCUTE_DIR=/path/to/mingcute-icons.scripts/embed-assets.shremains available for non-icon assets. - Include
mk/vendor.mkwhen your app enables curl or liboqs-backed features
Applications should keep build artifacts in their own build directories, but
the dependency source of truth and common build recipes should live under Kryon.
For TLS-enabled curl builds, mk/vendor.mk passes the OPENSSL_* make
variables through to the vendored curl CMake build.
Kryon owns the app command surface through kryon. From an app repository:
kryon build native
kryon build web
kryon build android-debug
kryon package linux-desktop
kryon package appimage
kryon previewFor local development against a sync backend, run a Daochi node in the
foreground. dev-backend locates the server source at $DAOCHI_DIR or as a
sibling checkout (../daochi), isolates its data under <project>/.kryon/, and
prints the sync URL to point your app at. Tokens are regenerated each start,
so it is for local development only:
kryon dev-backend # serves http://127.0.0.1:8080Apps can keep startup simple with one SyncNodePool: add the shipped public
node as SYNC_NODE_PUBLIC, add LAN or remote nodes learned through explicit
pairing as SYNC_NODE_PAIRED, then call RunSyncWithNodes. The pool tries a
paired local node first, another paired node second, and the public node last.
Temporary connectivity and authentication failures fall through automatically;
credentials and clock state remain isolated per node.
App project.kryon files should use target entries that call kryon
rather than embedding platform-specific build commands directly. Existing app
Makefiles can remain as backend glue while repeated native, web, Android, and
packaging logic moves into Kryon mk/ fragments.
Krait, the standalone Kryon IDE (a separate kryonlabs/krait repo that vendors
Kryon), previews .kry source by compiling it to an app host and loading it
into the embedded viewport. On each source change Krait rebuilds the project's
app host (make kryon-host, producing build/kryon/app_host.so), dlopens
it, and resolves CreateAppHost/DestroyAppHost. The build runs in the
background (fork + non-blocking pipe, drained each frame) so the window stays
responsive during the compile; once it finishes the new app host is loaded and
the preview updates. Source changes are polled a few times per second. Kryon
itself owns the preview host tooling (kryon-preview); it must not depend on
Krait.
A project can add project.kryon metadata such as preview_size,
preview_asset_root, and preview_scene to control the embedded viewport.
Kryon follows raylib-style C conventions where practical: lowercase module
filenames, simple C structs, and public functions named like raylib APIs
(InitWindow, DrawTexture, BeginUIFrame, ButtonNode). Internal helpers
stay private to src/ unless a downstream app needs the API in include/.
docs/API.mddocuments the public API.docs/KRY_LANGUAGE_SPEC.mdis the canonical.krylanguage and KIR contract.docs/FEATURE_MATRIX.mdmaps widget and feature support across the C, Go, and KRB targets and every renderer backend.docs/BACKENDS.mddocuments the backend architecture and selection.docs/BACKEND_CAPABILITIES.jsonis the checked backend inventory used by backend drift checks.docs/ARCHITECTURE.mdmaps the main Kryon subsystems and ownership lines.docs/BOUNDARIES.mddefines what belongs in Kryon and what stays in downstream applications.docs/PUBLIC_API_SNAPSHOT.txttracks public Kryon identifiers for API drift checks.docs/site/contains the static documentation website.docs/AGENTS.mddocuments how downstream apps should use Kryon, including modal/input capture and submodule update rules.
The ui_tk.h layer is Kryon's pragmatic Tk replacement surface. It stays in the
raylib style: one direct struct-and-call path per widget, caller-owned state,
immediate-mode drawing, and no builder objects or scripting runtime. The numbered
examples 09_geometry through 18_accessibility demonstrate each toolkit
feature family.
docs/KRY_LANGUAGE_SPEC.md is the canonical Kry language contract. Kry source
lowers into KIR, a debuggable intermediate representation with source spans.
From there k2c emits readable C for native apps, k2cpp emits C++ with C
linkage against the same C runtime, k2go emits pure Go source
against the native Go runtime, while k2b emits a portable .krb cartridge
(docs/KRB_FORMAT.md) for renderers that implement the Kryon runtime contract.
The intended tool set is Unix-shaped:
k2kir app.kry # .kry -> .kir
k2c app.kry|app.kir
k2cpp app.kry # .kry -> C++ (extern "C" decls over the C runtime)
k2go app.kry # .kry -> Go (native Go runtime, no cgo)
k2b app.kry|app.kir
Generated Go imports github.com/waozixyz/kryon/go/kryon as kryon and uses
clean qualified widget names such as kryon.Button, kryon.TextField,
kryon.Text, kryon.Row, kryon.Column, kryon.BeginFrame, and
kryon.EndFrame. Pure Kry and Go-native externs must not use import "C",
the removed bridge package, injected runtime objects, dot-imported runtime
names, or generated calls to stale prefixed C APIs. Explicit C externs with a
c. target, such as #extern "c.abs", are the opt-in exception: k2go emits
their import "C" bridge in a separate generated *_cgo.go file.
Handwritten Go can use the same package directly. Generated code keeps the
explicit props form (kryon.Button(kryon.ButtonProps{...}),
kryon.TextField(kryon.TextFieldProps{...})) for deterministic layout/state,
while app code may use shorter direct calls such as kryon.Button("Save") and
kryon.TextField("Name", &name).
The native Go runtime records each frame as pure Go FrameOp values available
through FrameOps(). That operation stream is the host boundary for native Go
windows/renderers: it carries resolved bounds, text, colors, focus, button
state, and redacted secure text without importing cgo or the removed bridge.
RenderFrame and RenderCurrentFrame provide a dependency-free software
renderer that turns those operations into an image.RGBA.
NewHost owns a persistent native Go runtime, runs generated or handwritten
frame functions, queues input, exposes frame operations, and renders frames
without cgo.
k2go output is compiled against that native runtime by the test suite, and the
generated Go/C parity tests drive both runtimes through the same scripted input.
This is an executable compatibility gate, not only a textual generated-source
check.
k2c, k2js, and k2b accept .kry source and run the KIR frontend
internally. Native platform, storage, and performance-sensitive C code remains
first-class through the C backend and through explicit KRB capabilities or host
imports.
