-
v1.3.3 Stable
released this
2026-09-22 22:11:36 +02:00 | 14 commits to main since this releaseUsagi v1.3.3 contains an important bug fix where gamepad input broke on web builds in v1.3.0.
Get the latest by running
usagi update, downloading the executable, or updating via the Homebrew package manager. Don't forget tousagi refreshto get the latest docs and Lua function signatures.Thanks to @curbs for all of the fixes and additions in this release!
Features:
gfx.text_exnow supports an optionalspacingparameter as the final argument for text spacing; see #124
Fixes:
- Gamepads no longer cause web builds to crash; see upstream sola-raylib #74
- Lua meta for LSP now has
textparam forgfx.textasanysince it now supports that; see #125
Downloads
-
Source code (ZIP)
8 downloads
-
Source code (TAR.GZ)
8 downloads
-
v1.3.2 Stable
released this
2026-09-14 20:52:45 +02:00 | 21 commits to main since this releaseFixes:
- GIF recording now works in DEV mode; it accidentally got disabled for all in
the v1.3.1 release; see
#117
Downloads
-
Source code (ZIP)
2 downloads
-
Source code (TAR.GZ)
1 download
- GIF recording now works in DEV mode; it accidentally got disabled for all in
-
v1.3.1 Stable
released this
2026-08-28 02:39:04 +02:00 | 26 commits to main since this releaseA small but important release with a bug fix for those using
usagi.conf. It
wasn't included in the exported game binary bundle, meaning the settings
wouldn't apply. That's fixed now, as well as some other bugs and additions
below.Download the executable below, run
usagi update, or update via Homebrew
if you install it that way.Features:
- New
util.ease.*functions by curbs; see
PR #104;
view the docs - Setting
gif_lengthconfig value to0disables the GIF recorder, removing
the small bit overhead associated; useful if you are developing or testing on
older hardware; see #69 - GIF recorder only runs in dev mode with
usagi dev; exported games and
usagi rundo not not run the recorder so that the overhead of running it is
not passed onto players, especially those on less powerful hardware; players
who want to record their gameplay have their own means and the GIF recorder in
Usagi is meant as an easy way for devs to share their game progress. It's also
imperfect since effects like screenshake don't come through. So it's now dev
mode-only. See #69
Fixes:
Downloads
-
Source code (ZIP)
5 downloads
-
Source code (TAR.GZ)
9 downloads
- New
-
v1.3.0 Stable
released this
2026-08-15 01:42:16 +02:00 | 42 commits to main since this releaseUsagi v1.3.0 fixes some annoying bugs with window sizing and scaling and
extreme memory usage by sfx. It includes a couple of nice features too,
like player setting for rotating the game. Devs can configure GIF
record length if they want longer ones.▶ Watch a video overview of this release!
But the big change is how config works. The
_configfunction that
returns the table of options still works, but it is now deprecated.
The new way is to createusagi.conffile:name = My Game game_id = some.unique.id.brettmakesgames.com pixel_perfect = trueYou can also just use magic comments at the top of your game's Lua
file, like:-- name = My GameSo long as it's the first line of the file. This is useful for single-file
games and devtools within an Usagi game.The motivation for the new way to configure Usagi games is that
the_configtable could lead to footguns whereusagi.GAME_W
and similar configurable values could be called before that
_configvalue is applied, leading to incorrect values. I think it's
better to separate the config from the game and not have this
be a problem at all.Also, by having it be an external file or simple
key = valuein comments,
it's easier to parse by external tools and scripts. Win-win.Thank you for the great community contributions in this release by
Achie, Goldenlion, Stew H, and Denis C!Features:
- Configure games with a
usagi.conffile or-- key = valuefrontmatter
comments at the top ofmain.lua, instead of a_config()function.
Frontmatter wins overusagi.conf, which wins over the now-deprecated
_config().usagi initcreates ausagi.conf. See
#55 - Config option for
gif_length(seconds) to support recording longer (or
shorter) gifs. See #98 - Game rotation setting in 90deg increments via the Pause menu's Settings; see
#79 - Warn when requiring files with different casing on the disk, as it can lead to
issues on different file-systems; see
#81 - The first arg for
gfx.textandgfx.text_exno longer need to be strings,
sogfx.text(10, 4, 4, gfx.COLOR_BLACK)renders 10 rather than erroring,
making for a more convenient API; if it fails to convert, it defaults to empty
string; see #99
Fixes:
Downloads
-
Source code (ZIP)
3 downloads
-
Source code (TAR.GZ)
2 downloads
- Configure games with a
-
v1.2.0 Stable
released this
2026-07-02 16:34:31 +02:00 | 67 commits to main since this releaseUsagi v1.2.0 is a release with a lot of bug fixes and a few nice features that
handle some of the more often requested capabilities. The highlights being
the engine and its exports now work on Intel Macs, new sfx functions for
more robust playback behavior, better window sizing behavior, and
an optional alpha parameter for mostgfxdrawing calls for shapes,
sprites, and text.Get the latest by running
usagi updateor downloading below. Don't forget
to runusagi refreshin your project(s) to get the latest docs and ancillary
engine files.Features:
- macOS builds are now a universal binary (Apple Silicon + Intel), so the engine
and exported games run on both without a separate download. Published as
usagi-<ver>-macos.tar.gz(with amacos-aarch64alias sousagi update
from older arm-Mac builds keeps working). See
#9 sfx.stop(name)stops every playing voice of a sound effect,sfx.stop_all()
stops all of them, andsfx.is_playing(name)reports whether any voice of a
sound is playing. See thesoundexample. See
#31- The pause menu's top view now shows a confirm/back input hint labeled for
whatever the player last used (keyboard keys or gamepad buttons). Hidden on
games shorter than the default 320x180 resolution, where space is tight; see
#49 - Running the
usagibinary with no arguments (double-clicking it or launching
a.desktopfile) now opens a launcher window; drop amain.luaor project
folder onto it to startusagi devon that path; see
#24 input.mouse_over()returns true when the cursor is over the drawn game area,
false when it's outside the window or over the letterbox bars; see
#41- Every
gfxdrawing call now takes an optional trailingalpha(opacity in
0..1); omit it for opaque. Covers the shape primitives (rect,rect_fill,
rect_ex,circ,circ_fill,circ_ex,line,line_ex,tri,
tri_fill,px) plustext,spr, andsspr. See theshapesexample.
See #53 usagi initnow creates emptysfx/,music/, anddata/dirs so new
projects show where sound and save files go; see
#32usagi.IS_RELEASE, the inverse ofusagi.IS_DEV, for gating release-only
code more readably; see
#37- Backspace acts as a cancel button in the Pause menu; see
#48 _confignow hasinitial_fullscreento launch the game fullscreen by
default, until a player toggles fullscreen and their choice is saved; see
#34- Reworked window scaling so pixel art stays crisp on high-DPI and
fractional-scaling displays instead of tearing or squashing pixels. Usagi now
turns off the OS high-DPI mode and scales the game in real pixels, which is
what makes integer scaling land on whole pixels; before, the OS scaled our
already integer-scaled frame again by a fractional factor, so the pixels came
out uneven. The starting window size is now picked relative to the display
(the largest integer scale that fills about two-thirds of it) rather than a
fixed 2x, so low-res games no longer open in a tiny window, and a game bigger
than the display opens maximized rather than hanging. Usagi also logs a
one-line display summary on boot to make future scaling reports easier to
debug. See #62,
#47,
#34, and
#36
Fixes:
- Warn at load when
sprites.pngexceeds a safe texture dimension (8192px per
axis). Oversized sheets get clamped by the GPU and render sprites past the
limit as black squares; the warning explains the cause and the grid-layout
fix; see #22 usagi loveifynow refuses when the destination is inside the source project
instead of recursing until it errors; see
#14- Reseting/clearing save data on web now works; see
#61 - Pause menu rectangle outlines properly render top-right corner on some GPUs
with fractional scaling; see
#60 - Alpha values now properly render; see
#51 - Don't register gamepad input when window is not focused; see
#28 - Tear down the entire Lua VM on game reset (a.k.a. hard reload) so there aren't
lingering variables/changes; this better matches dev expectations; see
#44 - Close pause menu when resetting with hotkey (e.g., Ctrl+R); see
#65 - Set 0.1s max on
dtso that there aren't weird gaps when resuming a game
after OS pause (browser tab not focused, computer wakes from sleep, etc.); see
#63 - Pause audio in web builds when tab isn't visible, fixing choppy playback in
that scenario; see #63 - Don't crash when attempting to reading a file that doesn't exist; see
#30 - The GIF recorder does not run for games higher res than 720 as it degrades
performance majorly; an info message is logged - Linux ARM (Raspberry Pi) builds now use OpenGL ES 2.0 so they boot on Pi
driver stacks that only expose GLES; desktop GL 3.3 could fail there with
GLXBadFBConfig. Linux ARM builds now use_es.fs(GLSL 100) shader
variants, same as web; see
#38
Downloads
-
Source code (ZIP)
10 downloads
-
Source code (TAR.GZ)
11 downloads
- macOS builds are now a universal binary (Apple Silicon + Intel), so the engine
-
v1.1.1 Stable
released this
2026-06-10 14:24:27 +02:00 | 163 commits to main since this releaseA patch-level release specifically focused on improving web performance.
Includes a couple of smaller additions that were already done but not
worth of a minor bump.Use
usagi updateto get the latest version or update through your package
manager. Thenusagi refreshin your projects to get the latest docs.Features:
usagi font bakegained five new script blocks, all included in
--scripts all:box-drawing(alias:box) for Box Drawing (U+2500–U+257F)
and Block Elements (U+2580–U+259F);arrowsfor U+2190–U+21FF;math(alias:
math-ops) for U+2200–U+22FF;geometric(alias:shapes) for
U+25A0–U+25FF; andsymbols(alias:misc-symbols) for U+2600–U+26FF. Box
drawing was the motivating gap. Fonts that lack these glyphs are unaffected;
the cmap filter drops the codepoints they don't cover. To keep an atlas small,
subtract the blocks you don't need, e.g.--scripts all,-symbols,-math. See
#16- Added support for the
?verbose=1query param to web builds to get diagnostic
logging to the console for debugging web build performance.
Fixes:
- Added
gfx.COLOR_TRUE_WHITEto meta Lua stubs/comments as the wrong white was
being used. - Improved web performance by only copying screen pixels from GPU to CPU for
games that callgfx.get_px, that way all games don't have to pay that cost.
This operation is seemingly slow on web. Showing about a 10% improvement in
performance from testing. See
#19
Downloads
-
Source code (ZIP)
8 downloads
-
Source code (TAR.GZ)
5 downloads
-
v1.1.0 Stable
released this
2026-06-04 20:42:20 +02:00 | 179 commits to main since this releaseUse
usagi updateto get the latest version or download below. Be sure to run
usagi refreshin your projects to get the latest docs and completion updates!Features:
- New
usagi loveify <src> <dst>subcommand: one-time port of an Usagi project
to a Love2D 11.5 project. Walks the source tree, rewrites compound-assignment
operators (x += 1→x = x + (1)) for LuaJIT compat, copies all assets
verbatim, and drops in the Love shim runtime (usagi_shim.lua+conf.lua)
plus the bundled monogram font when the source has no customfont.png.
Refuses to overwrite an existing destination. Intended as a graduation path
when a project needs iOS / Android, more action buttons, more robust APIs, or
other Love-only features. See the new "Graduating to Love2D" section in
README.md for the workflow and what's intentionally not carried over (pause
menu, input remapping, shader hooks, hot reload, FPS overlay). - Linux aarch64 is now a published export target. Released as
usagi-<ver>-linux-aarch64.tar.gzand produced by
usagi export --target linux-aarch64(also included in--target all).
Covers Raspberry Pi, ARM Linux handhelds, ARM SBCs, and ARM Linux VMs.
#270 usagi export --target hostfuses against the running binary regardless of OS
or architecture. This lets devs on platforms outside the published-template
set (e.g., macOS Intel, FreeBSD) build the engine from source and export for
themselves. Output filename is<slug>-<os>-<arch>.zip. On unsupported hosts,
the default--target allalso produces this zip alongside the published
builds, so the dev doesn't have to know about the flag. See
Building for unsupported platforms
in the README. #273- Lua's standard
debuglibrary is now available in user code. Use
debug.getinfo/debug.tracebackfor logger line numbers, and embed
step-debuggers like debugger.lua. Note that this exposes the full library,
includingdebug.setlocal/debug.setupvalue/debug.sethook. Those can
corrupt the VM if misused, so treat them with care.
#267 usagi font bakegained a--scriptsflag for picking which Unicode blocks
to include. Pass a comma-separated list of names, withall(default) and
noneas special values and a-prefix for subtraction. Known scripts:
latin,latin-ext,greek,cyrillic,punct,cjk-punct,hiragana,
katakana,hangul(alias:korean),cjk(alias:han),halfwidth.
Examples:--scripts all,-cjkto drop Han ideographs, or
--scripts latin,koreanfor a Korean-only atlas. The--no-cjkflag is now
deprecated and prints a warning; it stays as an alias for--scripts all,-cjk
and will be removed in a future major release.
#287
Fixes:
meta/usagi.lua(the LSP type stubs) now declaresgfx.COLOR_TRUE_WHITE. The
constant has always existed at runtime (slot0, pure white), but the stub
omitted it, so editors flaggedgfx.COLOR_TRUE_WHITEas undefined. The stub's
palette docstring also wrongly claimed slot0renders as a magenta sentinel;
it resolves to true white, and only indices above the active palette's length
render as magenta.- Added missing
util.remapfunction to bundled type definitions in
meta/usagi.lua. usagiCLI output now renders colorized in Windowscmd.exe. The colorized
[usagi]log prefix relies on ANSI escape sequences; modern Windows 10+
conhost understands them but only after a process opts in via
SetConsoleMode. Windows Terminal and PowerShell inherit the opt-in from the
parent process, but barecmd.exedoes not, so previously the sequences
printed as raw bytes ([32m[usagi][0m ...). Usagi now opts in once at
startup; on truly pre-Win10 hosts where the opt-in fails, color is suppressed
and the plain[usagi]prefix path takes over.
#286usagi font bakenow includes Hangul (Korean) and Latin Extended Additional
(Vietnamese precomposed forms) by default. Previously these blocks were
excluded, so even a font with full Korean or Vietnamese coverage produced an
atlas where every Hangul or Vietnamese codepoint rendered as?. The
examples/custom_fontdemo now includes a Korean line to verify coverage end
to end. #287- Calling
usagi.read_jsonorusagi.read_textat the top ofmain.luano
longer breaksusagi toolsandusagi export; see
#264 gfx.text_excalled with 6 args (missing the requiredalphaintroduced in
v1.0.0) no longer aborts the process on Windows; the error surfaces on the
in-game overlay like other malformed calls. As part of the fix, short-arg
calls to any wrapped engine API now report the missing argument by index ("bad
argument #N to '...' (T expected, got nil)") rather than a confusing "bad
argument #1 to 'type'" message.
#259- Type annotation for
_config()table to help with autocomplete; see
#255 sfx.play(name)called repeatedly no longer cuts off the playing copy. Each
sfx now has a pool of 8 voices that overlap; the 9th simultaneous play steals
the oldest. #258usagi toolsUI now scales when the window is resized. Renders to a 1280x720
canvas and blits scaled (with letterbox bars) to fit any window size. Launches
at the largest integer canvas multiple that fits the current monitor.
#269- Right clicking in web exports now works properly and does not show the
browser's right click menu. See
#13
Downloads
-
Source code (ZIP)
3 downloads
-
Source code (TAR.GZ)
1 download
- New
-
v1.0.0 Stable
released this
2026-05-19 20:22:14 +02:00 | 220 commits to main since this releasev1.0.0 of Usagi Engine is here! With it comes a promise of no breaking changes
until v2 (if that ever happens). 🐰 🎉v1.0.0 comes with a lot of nice additions based on feedback from people making
their games. And some critical bug fixes and improvements.Install Usagi v1.0.0:
- Use
usagi updateif you already have it installed; thenusagi refreshin your project(s) - Use the install script at https://usagiengine.com
- Download for your operating system below
Breaking:
- Pixel API renamed for consistency with the other shorthand primitives (
rect,
circ,tri,spr, ...). The writer is nowgfx.px(x, y, color), the
screen-pixel reader isgfx.get_px(x, y), and the sprite-pixel reader is
gfx.get_spr_px(index, x, y). The old names,gfx.pixel,gfx.px(x, y)
(two-arg reader), andgfx.spr_px, are gone. Find and replace in your code:
gfx.pixel→gfx.px,gfx.px(x, y)→gfx.get_px(x, y),gfx.spr_px→
gfx.get_spr_px. See #215 - Palette slot
0now resolves to true white (COLOR_TRUE_WHITE) instead of
the magenta out-of-range sentinel. Negative indices and indices past the
active palette's length still render as magenta, so the "obvious unknown
color" indicator survives for the common typo cases. gfx.text_exgained a required trailingalpha(0..1) param for parity
withgfx.spr_ex/gfx.sspr_ex. Pass1.0to keep the old behavior. The
simplegfx.textsignature is unchanged.
Features:
- New
usagi.read_json(path)andusagi.read_text(path)for loading arbitrary
game data (level layouts, dialog scripts, tuning configs) from a project-level
data/directory. Paths are forward-slash relative todata/, nested subdirs
supported (usagi.read_json("levels/01.json")). The wholedata/tree is
bundled byusagi export, so the same call resolves identically in dev and
shipped builds. Hot reload: any save to a data file pokes the same
script-reload path as a.luasave, so top-level
local levels = usagi.read_json("levels.json")picks up new bytes without F5.
Newexamples/level_from_jsonandexamples/level_from_csv(the latter shows
theread_text+string.gmatchpattern for simple CSV grids, since the
engine doesn't ship a CSV parser).
See #218 - New
usagi.to_json(t)returns a Lua table as a pretty-printed JSON string.
Shares the shape validator withusagi.save, so keys must be all strings or a
dense1..ninteger array (functions, userdata, NaN, and cycles still error).
Useful for devtools, structured stdout logs, and any other place you want JSON
without writing to the save file. Seeexamples/to_json.lua. - New
gfx.tri(x1, y1, x2, y2, x3, y3, color)and
gfx.tri_fill(x1, y1, x2, y2, x3, y3, color)for drawing triangle outlines
and filled triangles from three points. Filled-triangle vertex order is
auto-corrected so arrows, spaceship nosecones, and pointer shapes draw
regardless of how you specified the points.
See #211 - New
gfx.COLOR_TRUE_WHITEconstant: an off-palette pure(255, 255, 255)
white. Use it as the identity tint forgfx.spr_exandgfx.sspr_exwhen you
want sprite pixels to pass through unchanged. The Pico-8gfx.COLOR_WHITEis
slightly warm (255, 241, 232) and tints sprites a touch peachy if used as
the identity, which is fine if you want a warm look but undesirable if you're
after pure pass-through. Available in every API that takes a palette index
(gfx.text,gfx.clear,gfx.rect, etc.) and stays pure white even with a
custompalette.pngloaded. - New examples:
- scene_switching: how to define multiple scenes like gameplay, main menu,
etc. and switch between them
- scene_switching: how to define multiple scenes like gameplay, main menu,
- The credit for the open source code that Usagi depends on is now included in
the engine's archive, detailing the various licenses. These are also viewable
at https://usagiengine.com/third-parties. USAGI_VERBOSE=1now emits a one-shot startup snapshot at boot (build
profile, platform, GC params, resolution, sprite size, pause-menu / palette /
font source, script path, Lua heap after_init) plus a per-second frame
summary line (avg / p50 / p99 / max frame time in ms, count of frames over the
16.7 ms budget, current Lua heap KB). The frame summary catches silent perf
regressions of the "still runs but slower" shape; the snapshot pins the env
for bug reports. Zero overhead when the env var is not set.- New
examples/diagnosticsto exercise both: short-lived table allocs in
_updatewith controls to scale the rate, plus a one-shot burst button to
provoke a GC cycle. Run asUSAGI_VERBOSE=1 just example diagnosticsand
watch the terminal. - Raylib's own boot chatter and per-frame TEXTURE log are now gated on a
separateUSAGI_RAYLIB_VERBOSE=1, so the diagnostics stream stays readable.
Previously both sharedUSAGI_VERBOSE=1and raylib's per-frame log buried the
frame summary. Set both env vars when you need everything.
Fixes:
- GIF recordings now use 255 colors instead of the default Pico-8 color palette,
fixing an issue where exported GIF colors were wrong.
See #222 - macOS no longer prints the GLFW "regular windows do not have icons on macOS"
warning at startup. Cocoa never honored the per-window icon anyway, so the
call was a known no-op; the.appbundle'sAppIcon.icnsis the path that
matters there, and it's still generated atusagi export --target macostime. - Passing a non-UTF-8 byte sequence (e.g.
string.char(200)) to engine APIs
that take a string (gfx.text,gfx.text_ex,usagi.measure_text,
usagi.menu_item,sfx.play,music.play,gfx.shader_set, etc.) no longer
crashes on Windows. Bytes outside ASCII render as the U+FFFD replacement
character instead of erroring at the FFI boundary. - Error overlay text renders cleanly on Windows setups where the bundled font
was previously upscaled at a fractional ratio and came out blurred / curly.
The overlay now draws at an integer multiple of the bundled monogram's native
size. See #212 usagi.savenow rejects unsupported table shapes with a clear message instead
of either a cryptic serde error or silent data loss. Tables with sparse
integer keys ({[6]=1, [7]=2}), gaps in a 1..n array ({[1]="x", [3]="z"}),
or mixed string/integer keys now error up front and point at the workaround.
JSON only supports maps with string keys or dense1..narrays.
See #220- Fixed slow shutdown after long sessions: switched Lua from generational to
incremental garbage collection, which keeps the heap bounded during play so
closing doesn't stall sweeping accumulated dead objects on exit.
See #232 - Pause menu now always uses the engine's color palette (Pico-8) so that custom
color palettes don't inadvertently lead to illegible pause menu colors.
Downloads
-
Source code (ZIP)
2 downloads
-
Source code (TAR.GZ)
1 download
- Use