• v1.3.3 d131329272

    v1.3.3 Stable

    brettchalupa released this 2026-09-22 22:11:36 +02:00 | 14 commits to main since this release

    Usagi 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 to usagi refresh to get the latest docs and Lua function signatures.

    Thanks to @curbs for all of the fixes and additions in this release!

    Features:

    • gfx.text_ex now supports an optional spacing parameter 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 text param for gfx.text as any since it now supports that; see #125
    Downloads
  • v1.3.2 a5f9b58eb9

    v1.3.2 Stable

    brettchalupa released this 2026-09-14 20:52:45 +02:00 | 21 commits to main since this release

    Fixes:

    • GIF recording now works in DEV mode; it accidentally got disabled for all in
      the v1.3.1 release; see
      #117
    Downloads
  • v1.3.1 1f4b58fff8

    v1.3.1 Stable

    brettchalupa released this 2026-08-28 02:39:04 +02:00 | 26 commits to main since this release

    A 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_length config value to 0 disables 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 run do 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:

    • Exported games properly include usagi.conf, applying configuration values as
      expected; thanks to curbs for the fix; see
      #115
    • Save Inspector tool properly reads game_id from usagi.conf; see
      #108
    Downloads
  • v1.3.0 9fbc4a67c5

    v1.3.0 Stable

    brettchalupa released this 2026-08-15 01:42:16 +02:00 | 42 commits to main since this release

    Usagi 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 _config function that
    returns the table of options still works, but it is now deprecated.
    The new way is to create usagi.conf file:

    name = My Game
    game_id = some.unique.id.brettmakesgames.com
    pixel_perfect = true
    

    You can also just use magic comments at the top of your game's Lua
    file, like:

    -- name = My Game
    

    So 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 _config table could lead to footguns where usagi.GAME_W
    and similar configurable values could be called before that
    _config value 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 = value in 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.conf file or -- key = value frontmatter
      comments at the top of main.lua, instead of a _config() function.
      Frontmatter wins over usagi.conf, which wins over the now-deprecated
      _config(). usagi init creates a usagi.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.text and gfx.text_ex no longer need to be strings,
      so gfx.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:

    • Nudge window size a little when launching so it's not too tiny when close to
      an integer scale; see #82
    • Upstream fixes from sola-raylib relating to gamepad mappings and incorrect
      gamepad device identification; see
      #3 &
      #4
    • Optimize sound effect memory usage (~4x less RAM usage); see
      #95
    Downloads
  • v1.2.0 cfa4eb70de

    v1.2.0 Stable

    brettchalupa released this 2026-07-02 16:34:31 +02:00 | 67 commits to main since this release

    Usagi 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 most gfx drawing calls for shapes,
    sprites, and text.

    Get the latest by running usagi update or downloading below. Don't forget
    to run usagi refresh in 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 a macos-aarch64 alias so usagi 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, and sfx.is_playing(name) reports whether any voice of a
      sound is playing. See the sound example. 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 usagi binary with no arguments (double-clicking it or launching
      a .desktop file) now opens a launcher window; drop a main.lua or project
      folder onto it to start usagi dev on 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 gfx drawing call now takes an optional trailing alpha (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) plus text, spr, and sspr. See the shapes example.
      See #53
    • usagi init now creates empty sfx/, music/, and data/ dirs so new
      projects show where sound and save files go; see
      #32
    • usagi.IS_RELEASE, the inverse of usagi.IS_DEV, for gating release-only
      code more readably; see
      #37
    • Backspace acts as a cancel button in the Pause menu; see
      #48
    • _config now has initial_fullscreen to 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.png exceeds 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 loveify now 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 dt so 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
  • v1.1.1 5d61d84d42

    v1.1.1 Stable

    brettchalupa released this 2026-06-10 14:24:27 +02:00 | 163 commits to main since this release

    A 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 update to get the latest version or update through your package
    manager. Then usagi refresh in your projects to get the latest docs.

    Features:

    • usagi font bake gained 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); arrows for U+2190–U+21FF; math (alias:
      math-ops) for U+2200–U+22FF; geometric (alias: shapes) for
      U+25A0–U+25FF; and symbols (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=1 query param to web builds to get diagnostic
      logging to the console for debugging web build performance.

    Fixes:

    • Added gfx.COLOR_TRUE_WHITE to 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 call gfx.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
  • v1.1.0 7ea71ba515

    v1.1.0 Stable

    brettchalupa released this 2026-06-04 20:42:20 +02:00 | 179 commits to main since this release

    Use usagi update to get the latest version or download below. Be sure to run
    usagi refresh in 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 custom font.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.gz and 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 host fuses 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 all also 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 debug library is now available in user code. Use
      debug.getinfo / debug.traceback for logger line numbers, and embed
      step-debuggers like debugger.lua. Note that this exposes the full library,
      including debug.setlocal / debug.setupvalue / debug.sethook. Those can
      corrupt the VM if misused, so treat them with care.
      #267
    • usagi font bake gained a --scripts flag for picking which Unicode blocks
      to include. Pass a comma-separated list of names, with all (default) and
      none as 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,-cjk to drop Han ideographs, or
      --scripts latin,korean for a Korean-only atlas. The --no-cjk flag 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 declares gfx.COLOR_TRUE_WHITE. The
      constant has always existed at runtime (slot 0, pure white), but the stub
      omitted it, so editors flagged gfx.COLOR_TRUE_WHITE as undefined. The stub's
      palette docstring also wrongly claimed slot 0 renders as a magenta sentinel;
      it resolves to true white, and only indices above the active palette's length
      render as magenta.
    • Added missing util.remap function to bundled type definitions in
      meta/usagi.lua.
    • usagi CLI output now renders colorized in Windows cmd.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 bare cmd.exe does 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.
      #286
    • usagi font bake now 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_font demo now includes a Korean line to verify coverage end
      to end. #287
    • Calling usagi.read_json or usagi.read_text at the top of main.lua no
      longer breaks usagi tools and usagi export; see
      #264
    • gfx.text_ex called with 6 args (missing the required alpha introduced 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. #258
    • usagi tools UI 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
  • v1.0.0 4119ce2241

    v1.0.0 Stable

    brettchalupa released this 2026-05-19 20:22:14 +02:00 | 220 commits to main since this release

    v1.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 update if you already have it installed; then usagi refresh in 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 now gfx.px(x, y, color), the
      screen-pixel reader is gfx.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), and gfx.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 0 now 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_ex gained a required trailing alpha (0..1) param for parity
      with gfx.spr_ex / gfx.sspr_ex. Pass 1.0 to keep the old behavior. The
      simple gfx.text signature is unchanged.

    Features:

    • New usagi.read_json(path) and usagi.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 to data/, nested subdirs
      supported (usagi.read_json("levels/01.json")). The whole data/ tree is
      bundled by usagi 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 .lua save, so top-level
      local levels = usagi.read_json("levels.json") picks up new bytes without F5.
      New examples/level_from_json and examples/level_from_csv (the latter shows
      the read_text + string.gmatch pattern 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 with usagi.save, so keys must be all strings or a
      dense 1..n integer 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. See examples/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_WHITE constant: an off-palette pure (255, 255, 255)
      white. Use it as the identity tint for gfx.spr_ex and gfx.sspr_ex when you
      want sprite pixels to pass through unchanged. The Pico-8 gfx.COLOR_WHITE is
      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
      custom palette.png loaded.
    • New examples:
      • scene_switching: how to define multiple scenes like gameplay, main menu,
        etc. and switch between them
    • 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=1 now 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/diagnostics to exercise both: short-lived table allocs in
      _update with controls to scale the rate, plus a one-shot burst button to
      provoke a GC cycle. Run as USAGI_VERBOSE=1 just example diagnostics and
      watch the terminal.
    • Raylib's own boot chatter and per-frame TEXTURE log are now gated on a
      separate USAGI_RAYLIB_VERBOSE=1, so the diagnostics stream stays readable.
      Previously both shared USAGI_VERBOSE=1 and 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 .app bundle's AppIcon.icns is the path that
      matters there, and it's still generated at usagi export --target macos time.
    • 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.save now 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 dense 1..n arrays.
      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