Changelog

What changed, release by release

The notes published with each GitHub release, newest first. The complete history, including smaller versions that were tagged without a release page, is in CHANGELOG.md.

animaEngine 1.5.1

Latest

Release page

Animated PNGs, a way to hide the ⚙ button, and two fixes: for people coming from 1.2.0, and for sway and Hyprland.

What you’ll notice

  • Animated PNG (APNG) plays. Drop one in and it moves the way a GIF does, every frame for as long as it asks. One you added under 1.5.0, which stood still, plays now too.
  • The ⚙ button can be hidden. Appearance → Show the ⚙ button. With it off, its corner passes clicks like the rest of the overlay. Open edit mode with its shortcut, from the tray, or by starting animaEngine again from your apps — that always works, whatever your desktop has. In edit mode the button is there as the way out.

Fixed

  • Coming from 1.2.0, the characters looked as they did then, with no walk, fall or sleep: 1.2.0 left its pictures in the folder it was started from, usually your home folder, and 1.5.0 found those first. The ones 1.5 draws are used now. The old folder, assets/demo in your home folder, is left alone; you may delete it.
  • On sway, Hyprland and other wlroots compositors (native Wayland), the app quit when its monitor went — unplugging the monitor it was on, or on Hyprland starting it from exec-once before the monitors were up. It moves to a monitor that is there now, and waits while there is none.
Files of 1.5.1 (4)

animaEngine 1.5.0

Release page

The characters come to life, and the overlay finds a place in your day. Most of it is off until you turn it on.

What you’ll notice

  • They are alive, if you want them to be. Tap a character, even outside edit mode, and it hops, says one of its own lines and plays its sound, with a few hearts. Characters can follow one another, play tag, greet each other when they meet and bump into each other; they fade in and out, keep hours of their own, and can be livelier in the morning and slower at night.
  • Around your day. Reminders every so often or at a set time, said by a character in a bubble — and, if you like, as a desktop notification with a sound. A focus timer. Bedtime. Snooze for a while from the tray. While you are away they doze, and greet you when you come back. They step aside while a game, a video or a presentation fills the screen, or while an app you choose is in front, and can live behind your windows instead of over them.
  • Editing. Undo and redo (Ctrl+Z, Ctrl+Shift+Z). Select several characters — Shift+click or a rectangle — and move, change, group, line up or space them together; drags snap. Copy, cut and paste characters, or paste a picture copied in another app. Throw one.
  • Scenes and files. Save what is on screen under a name, with a picture, and switch between scenes from the Scene tab, the palette, the tray or on a schedule. Share a scene or one character as a single file, save a character as a GIF, and back up everything in one file to restore on another machine.
  • Sounds at the volume you want: one volume for everything and one for each character, quiet at bedtime, mute from the tray, a shortcut or D-Bus.
  • New global shortcuts: Super+Alt+A, H and P (Win+Alt on Windows) open edit mode, hide the overlay and pause, in a new config. The old Ctrl+Shift+A, H and P were taken from every app while this one ran — VS Code’s command palette, Firefox’s private window, KDE’s Deselect. An existing config keeps the shortcuts it has.
  • Without a mouse. Shift+F10 or the Menu key opens a character’s right-click menu, Ctrl+A selects every character, N steps through them, and Tab moves through the settings panel. The F-keys can be bound.
  • Lighter. The overlay barely works while nothing moves: hidden, snoozed, paused or asleep it wakes a few times a second, where native Wayland used to draw sixty frames a second, and a hidden overlay on X11 as many as a shown one. With several monitors, each one’s overlay draws only when something on it changes. It also starts sooner and sets up the GPU with less memory and fewer threads. And while characters move, it can draw thirty frames a second instead of sixty — always, or only on battery — at the same speed: on a laptop’s integrated GPU that halved the time drawing took.
  • Ten characters of its own, and a welcome. The ghost, the slime, the heart, the star and the cat are drawn again — outlined, lit, with eyes that blink — and a bunny, a frog, a robot, a cloud and a mushroom join them, in Library’s Built-in characters and the Meadow friends preset. They walk, fall, dangle when you pick them up and fall asleep when you are away, each with drawings of its own. The first time you open edit mode, a welcome lets you choose which of them are on your desktop, the language and whether the app starts at login. A new icon, too.
  • In your language, more of it. The tray, the presets, the reasons a file is refused, a first run’s characters and what delivers the global shortcuts were English in every language; they are translated now, in all ten, and the Keybindings tab names the keys as your keyboard labels them. A count is said as your language says that number — “60 de minute”, “5 postaci”.

Fixed

A selection of what was wrong before 1.5:

  • Global shortcuts on GNOME under Wayland — Ctrl+Shift+A, H, P — worked only while one of the app’s own windows had the keyboard. The app asked GNOME’s shortcuts portal before GNOME knew which app was asking, and fell back to an X11 grab. It says who it is now; the first time, GNOME asks you to allow the shortcuts, and the app waits for your answer for up to ten minutes.
  • Logging out or shutting down with the app running lost whatever it had not saved yet — edits still in edit mode, a pause from the tray. It saves on the way out now, as its own Quit always did.
  • Installed from a package and started from the desktop’s menu, the app made an assets folder in your home directory, for its demo characters’ pictures. They live in its data directory now; an ~/assets/demo folder left behind can be deleted.
  • Saving never wrote the sprite groups back: a deleted character’s id stayed in its group, and a character added later under the same id joined that group at the next start.
  • Native Wayland drew sixty frames a second whatever the scene did, and edit mode did on both backends.
  • Sounds stopped for good when the sound server restarted.
  • Leaving edit mode or hiding the overlay in the middle of a drag left the character frozen, or carried it to the pointer afterwards; on native Wayland with several monitors, hiding left the other monitors’ characters on screen.
  • The right-click menu of a character on another monitor opened on the wrong one; opened from the keyboard, no key reached it there and a screen reader did not see it — it now opens on the panel’s monitor.
  • On native Wayland at a scale above 1 — 150 %, 200 % — the settings panel came out twice its size, clicks on it missed, and everything was blurred. Each monitor is now drawn sharp at its own scale.
  • The settings panel’s footer covered the last row of a long tab, and the panel’s text fields had no copy and paste.
  • The settings panel grew wider in some languages, on the Keybindings tab in all of them, and a screen reader found some controls without a name.
  • On native Wayland, starting the app again while its characters were hidden did nothing; it shows them, as on X11.
  • A folder of PNG frames can be dropped, as one animation; a picture saved under the wrong extension is known by what it holds; and an unreadable picture is refused in your language, without the decoder’s jargon or the file’s whole path.
  • Tabbing through the settings panel scrolls it to the focused control; it used to go on out of sight below the panel’s edge.
  • The command palette finds a label typed without its accents — “atip” finds Ațipește, “theme” thème.
  • The tray’s menu caught up with a click only up to three seconds later: snoozed from it, it still offered to snooze. It changes at once now.
  • H and I only wrote to the log: H opens the Keybindings tab now, every shortcut, and I the Inspector. + raises the opacity on a US keyboard too, and on native Wayland Ctrl+Shift+H hides the overlay in edit mode, as on X11.
  • After an upgrade, a new action’s default could take a shortcut you had set, and the Keybindings tab could not remove a new action’s default.
  • Duplicate failed for the demo characters when the app was started from the desktop’s menu, and kept only a character’s size and opacity. It copies the whole character now.
  • Recording a shortcut, the key also did what it was already bound to: Escape left edit mode, S saved — on X11 a global one too, as Ctrl+Shift+P paused.
  • The frame cache kept every picture at its full size, and each start made it smaller again: a 1024² sequence of 24 frames took 96 MB on disk for the 6 MB it uses. It keeps them as they are shown now.
  • “Reset onboarding hints” did not bring “What’s new” back, and a tour started again began at its last step.
  • Two warnings could be written every frame — an X11 window on another monitor, a picture read back on Windows — and fill the log; each is said once now. A character listed in two groups did the same.
  • Building from source as the README said stopped on a clean system: a library it needed was missing from the list, and six it named were never used. The AUR package did not build on current Arch at all; it does again.
  • A GIF cut short, dropped or added from the library, froze the app and filled the log. Its frames before the cut show, or it is refused if there are none.
  • With more than 256 pictures in the library, the Library tab would not open. It does, and a broken file in it, or dropped, says why in your language; a file deleted from the library folder leaves the list.
  • From the keyboard or a screen reader, the time fields took no arrow keys and seven lists stayed open after a choice; renaming a group typed in front of its name.

Changed

  • A new app id, eu.animaengine.Anima, after the project’s domain, animaengine.eu. If you pinned animaEngine to your dock, pin it again; a desktop that granted its global shortcuts asks once more. Shortcuts bound in sway, Hyprland or river with the old D-Bus name keep working.
  • On a laptop with an NVIDIA GPU beside an integrated one, the NVIDIA GPU is left asleep: loading its driver woke it, and starting and quitting each took some 3 s longer. prime-run still draws on it.
  • Lighter with nothing moving. Characters animating at the same rate change frames together now: five standing still draw a third of the frames they did, and the compositor, which redraws the screen for each, does a quarter of the work.
  • On X11 with a screen scale factor above 1, the characters are drawn at it too, as the panel always was: at 200 % they were half the size they are on native Wayland.
  • Sharp on a HiDPI screen. A picture larger than 256 pixels was kept at 256 and, on a 200 % screen, drawn twice as large. It is kept at the screen’s scale now, up to 512 pixels, and shows at the same size — on each monitor, at its own scale.
  • Messages show outside edit mode too, in the bottom-right corner, and clicks go through them: one raised while the panel was closed — a reload, a refused file, a pause from the tray — was gone before anyone opened it.
  • Cycle character is on N. Tab belongs to the settings panel’s focus, where it never cycled on X11 and only once on native Wayland. A config that still had Tab there as it came moves to N; one set by hand stays.
  • A config written by a newer version no longer costs the whole file, nor does a scene, a shared file or a backup: what this version cannot read is left out, with a banner or a toast, and kept in the file for the version that wrote it.
  • Five things are on from the start, each with its switch: stepping aside for full-screen apps, dozing after ten minutes away and the welcome back, the little effects, and snapping while dragging.

Security

From an audit of 1.5 (security-audit-2026-10-15.md, in Romanian) and the fuzzing of every new file reader:

  • Every picture is decoded within the same limits on its size and memory, whichever way it arrives; a GIF or WebP that claimed a huge frame could ask for gigabytes, and a cut-short GIF looped forever.
  • Desktop notifications escape their text: a reminder from a restored backup or a name from a shared scene could carry links or images to a server that reads markup.
  • A paste from the X11 clipboard has a deadline, and a script’s output goes to the debug log only.
  • 23 crates left the build (URL and ICU parsing, a browser launcher) with a link feature the app never used; the others are at their latest compatible versions.

Compatibility

  • Upgrading: additive. A 1.4 config loads with every value kept — configs written by 1.0 and 1.4 themselves are test fixtures now.
  • Going back to 1.4 or earlier: they read a 1.5 config as long as it holds nothing they lack. Once it does — a character that follows another or plays tag, say — they start with the default scene and keep your file beside it as config.toml.bak-corrupt; copy it back after upgrading again. (Checked both ways with a build of 1.4.0.)
  • D-Bus: new methods StartFocus, StopFocus, Snooze, Wake, NextScene, SetMuted and ToggleMute; the old ones are unchanged.
  • Flatpak: two more read-only D-Bus names, for the idle time (org.gnome.Mutter.IdleMonitor) and the battery (org.freedesktop.UPower).
  • The frame cache is in a new format: the first start after the upgrade decodes each picture again, once, and replaces the old file.
  • New setting: [global] frame_rate (smooth, light, light_on_battery); 1.4 ignores it.
  • No change to the CLI, or to where the config and the data live; 1.5 adds folders inside them: scenes/ beside config.toml, and demo/ in the data directory for the first characters’ pictures. See stability-policy.md.

Known gaps in verification

Everything in 1.5 was run in the headless test rig on both backends — sway with software rendering, a private D-Bus and PipeWire, stand-ins for the portals, Mutter’s idle monitor and the notification server — plus the X11 shortcuts and two monitors on a real X server, the .deb and the AppImage built by the release scripts and run, and the unit tests under Wine. On the maintainer’s laptop (GNOME on Wayland, an AMD integrated GPU beside a sleeping NVIDIA one) the installed .deb ran: the shortcuts portal took the session, the NVIDIA GPU stayed asleep, and the GPU time of thirty and sixty frames a second was measured. Still to be checked there, with a sound card, Orca and the AppIndicator tray: the list in gnome-checklist-1.5.md. The Windows build compiles and its unit tests pass under Wine; it has not run on real Windows. The new text is machine-translated in nine of the ten languages.

The full list is in CHANGELOG.md.

Files of 1.5.0 (4)

animaEngine 1.2.0

Release page

Characters can now be scripted. A behavior can be a small Rhai program from your asset library, and a script can play sounds that come from where the character is on screen and react to how busy your machine is.

The rest of the release is fixes, found the way 1.1’s were: by running the overlay and looking at it. This time that also meant a real X server for the X11 behaviour the test compositor cannot show, and building the missing tools — a Wayland drag source, a stub tray host — to exercise features that had never actually been seen working. Several had not.

What you’ll notice

  • Scripted behaviors. Pick Script as a character’s behavior in the Inspector and point it at a .rhai file in your asset library. Scripts are sandboxed — no files, no network, no processes — and bounded, so a runaway one is stopped and the character holds still. Five worked examples are in docs/examples/behaviors/.
  • Sounds. A script can call play("chirp.ogg"), and the sound is panned to where the character is: a mascot on the left of the desktop is heard on the left. WAV, OGG, FLAC, MP3 and the audio track of an MP4.
  • Machine load. Scripts can read cpu and mem, overall load from 0 to 1 — totals only; there is no way for a script to learn what is running. Linux only.
  • Shortcuts work on any keyboard layout. AZERTY, QWERTZ, Cyrillic: letters follow what is printed on the key, the number row its position. German shows Strg instead of Ctrl.
  • Your config is no longer replaced by the demo scene. A config that listed only the settings it cared about failed to load, and the next launch backed it up and overwrote it with the defaults, without a word on screen. Every setting now has a default, and when a config really cannot be read, a banner says so and where the original was kept.
  • On native Wayland, file drops and the tray icon work — for the first time; both were listed as supported, and neither had ever worked there. In pass-through, drag the file over the ⚙ corner first; from there the whole screen accepts the drop.
  • Ctrl+M no longer makes a character disappear. Moving a character to another monitor pinned it there without moving it, so it was drawn off the edge of that screen. It now moves across.
  • anima-engine --version prints the version.

Under the hood

  • One copy of the event handling. The context menu, the command palette, the Library’s “Add to scene”, hot-reload, file drops and Shimeji import each had one implementation per backend, and the copies had drifted: a stale selection after applying a preset on Wayland, a toast in English on X11, a Shimeji import that froze the Wayland overlay. They now share one module.
  • Hardening: a malformed MP4 can no longer close the app, a small sound file can no longer decode into gigabytes, and concurrent writes to the same file can no longer interleave.
  • Translations: German, Dutch and Spanish each address you one way throughout instead of switching between formal and informal, and a test now fails on any notification built from untranslated text.
  • CI builds the Windows and FreeBSD ports on every push. The Windows port gained a tray icon and single-instance handling; its unit tests pass under Wine.

The full list is in CHANGELOG.md.

Packaging

  • ALSA is now a dependency, for script sounds: the AUR package depends on alsa-lib, and the .deb picks up libasound2 automatically. Building with --no-default-features --features video leaves sound out.
  • The Flatpak asks for the PulseAudio socket, without which it cannot make a sound. That socket also carries recording — Flatpak has no playback-only permission — so what keeps the app away from your microphone is that no capture code is compiled in, not the sandbox. See threat-model.md.

Compatibility

A config.toml from 1.0 or 1.1 loads unchanged; the D-Bus methods, the existing CLI flags, the accepted asset formats and the file locations are the same. The script behavior and --version are additions. See stability-policy.md.

One correction: the docs had named the config and cache directories ~/.config/animaEngine/ and ~/.cache/animaEngine/. On Linux they are, and always were, lower-case — ~/.config/animaengine/config.toml. If you ever hand-edited a config at the documented path, the app never read it.

Not in this release

  • Windows is not supported yet. The port compiles and its tests pass under Wine, but it has not been run on Windows.
  • Nine of the ten locales are machine-translated for the strings added here, and still want a native-speaker pass.

Known gaps in verification

Checked on a headless compositor with a virtual pointer and keyboard, both backends, and on a real X server for pointer and window behaviour. Not verified: sound output (the test setup has no audio device), multi-monitor on real hardware, the Flatpak build, and anything on Windows. docs/runtime-findings.md has the detail.

Files of 1.2.0 (2)

animaEngine 1.1.0

Pre-release

Release page

The first release after 1.0, and the first one shaped by actually running the application rather than only reading it.

Everything before this was verified the way a library is verified: unit tests over the parsers, fuzzing over the byte-facing code, a memory soak, static review. All of that held — and none of it could see that the command palette never opened, that the “+ Add” button in the keybindings tab was painted over by the row beneath it, or that dragging a character was not implemented at all on the native Wayland backend. Those are things you only find by putting the overlay on a screen and clicking it.

So this cycle built a harness that does exactly that: a headless compositor, a virtual pointer and keyboard, and screenshots. It found eighteen defects. Several of them made whole features unreachable.

What you’ll notice

  • Poke. Tap a mascot in edit mode and it reacts. Previously a tap was swallowed as a zero-distance drag.
  • Hover-startle. Mascots recoil from an approaching cursor. There’s an Appearance toggle if you’d rather they didn’t.
  • Dragging works on native Wayland. Left-click selects a character and you can drag it around. On that backend, selection was right-click only and drag did not exist — the core interaction of a desktop-pet overlay was missing, and the module’s own documentation implied otherwise by leaving it off the limitations list.
  • Ctrl+K works again, along with Ctrl+A/C/V/X/Z and shift-selection in every text field. On native Wayland the modifier state reaching the UI was hardcoded to “nothing held”, so every modifier chord silently did nothing. The same bug meant recording a new binding stored “Ctrl+Shift+X” as a bare “X”.
  • The keybindings tab is usable. Rows no longer paint over each other; the “+ Add” button of any action with two chords is no longer completely hidden behind the next row.
  • Clicking the settings panel no longer discards your selection.
  • The Light theme’s inactive tab icons are readable — they sat at 2.11:1 against a 3:1 requirement, and that tab bar is icon-only, so the glyph is the control’s entire label.
  • Ten locales stopped showing English. The whole behaviour picker drew hardcoded strings while its translations sat unused in every .ftl file.

Under the hood

A long list of correctness and hardening fixes — bounded reads across the untrusted-input surfaces, 0600 on config and crash files, path redaction in logs, a single saving shutdown path, entity ids that can’t collide, unbounded polls and event waits given limits. The full list is in CHANGELOG.md.

Two of the fixes are worth calling out because of what they say about the gaps that were closed:

  • cargo test was deleting and rewriting 34 committed files. The demo generation test pointed the process at the repository, removed assets/demo, and regenerated it in place. It left the working tree dirty with a diff no review would catch — binary, one pixel, identical file size — and would have destroyed the shipped assets outright if a generator had panicked midway.
  • Two new tests close the classes that hid these. One asserts every English message key is actually referenced by the code; the existing parity test proved translations existed, but nothing proved the app asked for them. The other asserts WCAG contrast for the ordinary Dark and Light palettes, which had no such guard — only the two high-contrast themes did.

Compatibility

No change to the config schema, the D-Bus surface, the CLI flags, the accepted asset formats, or the XDG paths. A config.toml from 1.0.0 loads unchanged. See stability-policy.md.

Not in this release

  • Windows is not supported. This release contains groundwork for the port — an OverlayPlatform trait, target-gated Linux/BSD dependencies, and a Windows backend skeleton — but that skeleton has never been built or run on Windows. It can’t be meaningfully cross-compiled from Linux, and no CI job covers it. It’s scaffolding, not support.
  • Nine of the ten locales are machine-translated for the strings added here and in 1.0.0, and still want a native-speaker pass.

Known gaps in verification

Recorded honestly, since this release is largely about the difference between “tested” and “verified”:

The headless harness covered the native Wayland path in English and German. Not yet exercised interactively: the winit/X11 path (no compositing X server was available), Shimeji pack import, file drag-and-drop onto the overlay, preset Append/Replace, multi-monitor visual behaviour, the two high-contrast themes, and the eight remaining locales. docs/runtime-findings.md keeps that map, along with the reproduction recipe and the traps involved in driving a Wayland compositor from a test.

Files of 1.1.0 (2)

animaEngine 1.0.0

Release page

The stable 1.0 release. animaEngine renders multiple animated characters over your Linux desktop — transparent, click-through, GPU-accelerated, X11 and native Wayland — in Rust on wgpu + winit. No Electron, no Chromium.

This is the end of a three-candidate bake (rc1 → rc3) plus an external security/robustness audit. rc3 ran as a public prerelease for about two weeks with no regressions. What changed across the candidates is in CHANGELOG.md; the short version is that every error path got probed, a memory soak came back flat, and the issues an audit found — a broken single-instance handshake, a config loader that could panic or overwrite your scene, a Shimeji importer that followed symlinks, a thumbnail path escape, live dependency advisories, and an AppImage that linked too-new a glibc — are all fixed.

Highlights

  • Overlay that behaves. Click-through by default; the ⚙ button and panels stay interactive. Always-on-top, skips the taskbar, no focus steal. X11 (XShape/EWMH) and native wlroots layer-shell.
  • Drop to add. PNG / GIF / WebP / JPEG / MP4, with size and dimension caps enforced before decode.
  • Shimeji import, tray icon, global hotkeys, multi-monitor.
  • Durable config. Atomic writes, schema migration with backups, and a hot-reload that never overwrites your file on a bad edit.
  • Honest supply chain. SBOMs embedded in every artifact, build provenance attestation, a strict dependency-audit gate.

Install

  • .deb (Debian/Ubuntu) and AppImage (built on glibc 2.35, runs on every current mainstream distro) from this release’s assets. Verify with the attached SHA256SUMS.
  • Flathub and AUR follow shortly after this tag (they publish from separate repositories).

See install-verification-1.0.md for the from-scratch install checks per channel.

Thanks

To everyone who ran the candidates on their actual desktops and filed what broke. That’s what made the bake worth doing.

What’s next

Cross-platform: BSD, then Windows, then macOS, via an OverlayPlatform abstraction — the overlay layer is the only OS-specific part. The plan is in cross-platform-plan.md.

Files of 1.0.0 (2)

animaEngine 1.0.0-rc3 — audit hardening

Pre-release

Release page

Third release candidate. An external review of the rc2 tree (commit 88e0d5f, ~29.8k lines) went looking for the things a self-audit tends to miss — live dependency advisories, panic paths in the config loader, and the write side of code whose read side was already guarded. It found five real issues. rc3 is those fixes and nothing else; the memory soak is still flat and the published artifacts still check out.

Security

  • Three live advisories patched. quick-xml 0.37 → 0.41 (RUSTSEC-2026-0194 quadratic attribute parsing, -0195 unbounded NsReader allocation) and crossbeam-epoch → 0.9.20 (RUSTSEC-2026-0204). The quick-xml bump matters most: it’s the direct dependency that parses untrusted Shimeji pack XML, so the only path an attacker’s file could reach is now on a fixed release. Two transitive copies remain — a build-time proc-macro and accesskit’s own D-Bus introspection XML, neither fed untrusted input — with documented ignores kept in lockstep between cargo audit and cargo deny.
  • Shimeji symlink guard fixed. The pack size/count walk followed symlinks because it stat’d through metadata(); its is_symlink() check could never fire. A link inside a pack could send the walk out of the pack tree. It’s now detected and skipped. (The sprite copy path was already contained by canonicalisation, so no file was copied out — this was the stat walk.)
  • Thumbnail write path contained + decode capped. An asset id from a hand-edited library.toml could contain ../ and push a written thumbnail outside the cache directory; ids are now restricted to a safe filename component. And the thumbnail decoder now enforces the same MAX_IMAGE_DIM limit as the scene loader, so a small file declaring enormous dimensions can’t exhaust memory in the thumbnail thread.

Fixed

  • Config loader can’t panic on a bad version. version = 4294967296 used to wrap to 0 and hit an unreachable!; it now clamps to the current schema and skips migration, like any other malformed version field.
  • Future configs load read-only. A config from a newer build is no longer silently downgraded to the current schema on load.
  • Hot-reload never overwrites your config. A partially written file (an editor mid-save) or a hand-edit typo used to be replaced with defaults by the reload worker. Reload is now read-only: on a bad read it keeps the running scene and tells you the edit hasn’t taken.

How to help the bake

Same as before: run it on your actual desktop and file an issue if anything regresses — distro, session type (X11 / Wayland + compositor), and RUST_LOG=anima_engine=info output up to the problem. The import and hot-reload paths got the most churn this round, so exercising a Shimeji import and a live config edit is especially useful.

Files of 1.0.0-rc3 (2)

animaEngine 1.0.0-rc1 — the first 1.0 release candidate

Pre-release

Release page

This is a release candidate, not the final 1.0. It exists to bake: run it on real desktops for a couple of weeks and report anything that breaks before 1.0.0 is tagged. Only RC-blocker fixes land between now and the release.

What changed since 0.9.0

The headline is parity and hardening, not new toys — the freeze held.

  • The native Wayland path caught up to X11. With ANIMA_USE_WAYLAND_NATIVE=1 on a wlroots compositor, the asset library, the right-click context menu, and per-monitor distribution (a sprite-only layer surface per output) now all work. Exercised against a real headless sway, output hotplug included.
  • GNOME got usable. GNOME on Wayland — Ubuntu’s and Fedora’s default — runs through XWayland, where Mutter kept sinking the overlay behind focused windows and occasionally swallowing click-throughs. The overlay now re-asserts always-on-top and self-heals its click-through region, so characters stay on top and clicks reach the windows beneath them. One honest limit remains: a click can’t pass through to a native-Wayland window underneath — that’s the XWayland boundary, tracked for after 1.0.
  • The settings panel is lighter — icon-only tabs and a frosted, semi-transparent panel.
  • A pile of fixes found by building and running from source on Kali, Fedora, Arch, and Alpine: a HiDPI / fractional-scale bug that pushed the ⚙ toggle button off-screen, multi-monitor crashes on the Wayland path, atomic crash snapshots, a memmap2 security advisory, and the build-dependency gaps each distro surfaced (pkg-config, libxkbcommon-x11-dev, the Alpine musl -crt-static flag).

The 1.x promise

From 1.0 onward your config.toml, the org.animaengine.Anima D-Bus methods, the CLI flags, and the documented environment variables are stable across the whole 1.x line — see the stability policy.

How to help the bake

Run it on your actual desktop. File an issue if anything regresses from 0.9.0, with your distro, session (X11 / Wayland + which compositor), and the RUST_LOG=anima_engine=info output up to the problem.

Files of 1.0.0-rc1 (2)

animaEngine 0.9.0 — the stability freeze

Release page

The release before 1.0 deliberately ships no new features. Its job is to prove the 1.0 contract before promising it: measure what the 0.6–0.8 cycles built, harden the edges, and make the docs tell the truth. Feature work stopped the day this phase opened; everything here is migration safety, leak hunting, fuzzing, and audit.

Config that survives its own future

A top-level version key now records the config schema generation. Files written before 0.9 have no key, are treated as schema v1, and migrate on load — but the original is copied to config.toml.bak-v<n> before any migration runs, so a migration bug can never be why you lose a config. A malformed version is treated as current rather than risking the wrong migration, and unknown [section] tables (e.g. from a newer build) survive a load → save round-trip instead of being dropped. v1→v2 is an honest identity migration — every change so far was additive — but the chain, backup, and forward-compat are in place and tested for the first change that isn’t.

Proving memory is bounded

  • Soak harness (scripts/soak.sh): a 16-entity synthetic scene under Xvfb, RSS least-squares-regressed against time to catch slow leaks. The regression fits the steady state only — a cold start legitimately steps memory once as the cache fills, and fitting across that step would cry “leak” on a flat run.
  • Leak audit: every pre-registered suspect came back bounded with a cited mechanism. The one real growth was the on-disk decode cache (content-addressed keying orphans a file on every asset edit, never reclaimed); cache::sweep now evicts oldest-first past a 1 GiB cap at startup, off-thread.
  • Perf HUD GPU block: the overlay (`Ctrl+Shift+``) shows a VRAM estimate, live texture count + uploads/frame, and draw calls — the same numbers the soak harness regresses, live.

Hardening

  • GPU surface-loss recovery. A lost surface reconfigures in place for the transient cases (resize, occlusion, the first frames after suspend); a loss that persists past a threshold — driver reset, GPU hot-unplug, device lost across S3 resume — rebuilds the whole renderer from the retained window, and exits cleanly for a restart if even that fails, rather than spinning on a dead device.
  • Expanded fuzzing. Three new cargo-fuzz targets over the hand-written parsers closest to untrusted bytes: the on-disk cache codec, the MP4 NALU length-prefix walk, and the Shimeji actions.xml reader, with committed seeds and a nightly CI run.
  • XWayland fractional-scaling click-through is now detected and warned about at startup instead of leaving misaligned clicks a mystery — an inherent XWayland limitation, documented with the workarounds.
  • Forward-compat with the upcoming rustc float-literal inference change (caught by the weekly beta-toolchain canary before it became a hard error).

Docs that match the code

  • Reality audit: every docs/*.md diffed against the code. config.md now documents every field (it was missing themes, locale, monitor mode, the per-state animation sets, the windows / groups / keybindings sections, and several env vars); the architecture diagrams were reconciled with the post-0.6 module layout; the threat model’s stale claims were corrected (the AccessKit bridge is a live flag, hotkeys are rebindable, release artefacts carry Sigstore provenance, and the native-Wayland path is now near-parity through the same drag-drop validation boundary).
  • Cross-locale audit: 194 keys × 10 locales came back clean on key parity and placeholder parity — and the placeholder guarantee is now a test, so a translator dropping a { $var } fails CI. The sweep fixed six corrupted strings from an earlier batch.
  • Freeze rules published. CONTRIBUTING.md declares the bugfix-only window to 1.0: what qualifies (crash, data loss, regression, security, doc error, translation), what waits, and how exceptions get decided.

Audit notes (1.0-grade)

A full-tree re-audit, treated like the 0.5.0 pass. The panic surface is clean: three unsafe blocks (two getuid, one wgpu surface handle, all justified), and every production .unwrap() is either bounds-guarded (the cache codec, also fuzzed) or a set-then-read invariant. The D-Bus surface is five parameterless methods — no untrusted IPC input. Env vars parse with fallbacks; size math is checked/saturating throughout, gated by the decoded-bytes budget. Findings were fixed or formally accepted in docs/threat-model.md.

Known limitations (accepted for 1.0)

  • openh264 runs in-process, unsandboxed. MP4/H.264 playback reaches Cisco’s C decoder; we bound the input (caps, a pure-Rust demuxer that pre-validates, a fuzzed NALU walk) but don’t isolate the decoder. A seccomp-confined decode thread is the right fix and is deferred past 1.0. If you don’t play video, nothing reaches it.
  • A native-Wayland device-loss rework and an App struct split are deliberately deferred — both are out of scope under the freeze.
  • The visual a11y matrix and a screen-reader walkthrough still want a human at a real session (tracked in docs/ux-audit-0.8.md).
# Debian / Ubuntu
sudo apt install ./anima-engine_0.9.0-1_amd64.deb

# AppImage
chmod +x animaEngine-0.9.0-x86_64.AppImage
./animaEngine-0.9.0-x86_64.AppImage
Files of 0.9.0 (2)

animaEngine 0.5.5 — hardening + engine correctness + frame pacing

Release page

Release driven by two external reviews of the post-0.5.4 tree, plus an engine-correctness pass that came out of verifying their claims against the code. The first review flagged stale docs, soft-fail supply-chain checks, a second-granular cache key, and a missing aggregate memory budget. The second caught two subtle animation-timing bugs and a world-writable-/tmp weakness in the XDG fallback dirs. Auditing those claims surfaced three more issues both reviews missed: a quad-budget off-by-two, GPU textures leaking on preset Replace, and a render loop redrawing at 60 Hz around the clock for a fully static overlay. None of these are exploitable on a cold start.

Idle-aware frame pacing

The biggest change in this release. The render loop previously requested a new frame unconditionally — the overlay re-rendered an unchanged scene at display refresh, 24/7, GPU and CPU awake the whole time. Scheduling is now derived from live state at the end of every frame:

Scene state Wake-up cadence
Edit mode / toasts / behaviors / physics / perf overlay display refresh
Only sprite animations playing soonest next-frame deadline (8 fps sprite → 8 wake-ups/s)
Fully static 2 s hot-reload heartbeat, zero GPU work between

Input (mouse, keyboard, drag-drop, tray, egui) wakes the loop immediately; config hot-reload keeps applying even while the overlay is hidden. The native-Wayland path is already compositor-paced by frame callbacks and is unchanged.

Animation correctness

  • Frame skip walked wrong on per-frame delays. Animation::tick divided the whole elapsed span by the current frame’s duration when skipping — correct for fixed-FPS, wrong for GIF/WebP per-frame delays, where a stall landed on the wrong frame with a desynced clock. Skips now walk frame by frame, each consuming its own duration, capped at two loops before resyncing (system suspend protection).
  • BounceOut silently shortened the loop. The bounce curve is not monotonic, so raw boundary deltas went negative between bounces and got clamped to 1 ms downstream. Intervals are now |delta| normalised over the loop: all non-negative, sum exactly the loop duration, monotonic curves unchanged to the bit.

Renderer fixes

  • MAX_QUADS off-by-two. The quad budget equalled MAX_ENTITIES, but the renderer reserves two UI slots mid-loop — a legal 64-entity scene dropped its last sprites and warned at 60 Hz in journald. Budget is now MAX_ENTITIES + 3; the overflow warning fires once per episode.
  • GPU texture leak on preset Replace. None of the three reset_to_configs call sites dropped replaced entities’ textures; VRAM grew on every Replace. Both render loops now prune textures whose entity no longer exists (two-integer no-op in steady state).

Hardening

  • /tmp fallback ownership. When XDG resolution fails, config/cache/data fell back to $TMPDIR/animaEngine-<uid> — a path any local user could pre-create and own (sticky-bit /tmp allows it), landing our atomic writes in a directory they control. The fallback now prefers $XDG_RUNTIME_DIR (0700, uid-owned by spec), and otherwise creates the tmpdir 0700 and verifies it: real directory, not a symlink, owned by our uid, no group/other bits — retrying once with a pid-suffixed sibling before giving up loudly.
  • Stale-index panic trap. Selection-driven keyboard actions indexed entities[idx] directly, relying on every removal path remembering to deselect. All dispatch arms now bounds-check and no-op instead.
  • Video loader log redaction — three lines missed the M4/G.1 sweep; redacted filename at warn!/info!, full path at debug!.

Launcher icon (finally) renders

The app icon showed as a blank tile in the GNOME Shell app grid since 0.2.0. Root cause: the SVG began with an XML prolog and a long design comment, and gdk-pixbuf — the pipeline GNOME Shell renders launcher icons through — sniffs the file’s first bytes for <svg (librsvg’s loader signature is anchored at the start). It never matched, so the Shell silently rendered nothing. rsvg-convert, Inkscape and image viewers all parse the XML properly, which is why every earlier check “confirmed” the icon as fine. The SVG now starts with the literal bytes <svg; the constraint is documented in packaging/icon-variants/README.md so a future icon swap can’t regress it.

What’s fixed in 0.5.5

Cache key was second-granular

hash(canonical_path + mtime_seconds) collapsed every sub-second mtime into the same key. A cargo build && edit asset && cargo build cycle inside one wall-clock second could therefore load stale RGBA on the second run. The key now hashes canonical_path + mtime_nanos + size + child_count:

  • nanoseconds for ext4 / btrfs / xfs / APFS mtime resolution,
  • size to disambiguate the rare cases where the filesystem floors mtime to the second (FAT32 / SMB shares / restored backups),
  • child count so adding or removing a frame inside a PNG sequence invalidates the key even when neither mtime nor total size moves measurably.

Existing cache files become orphans on first upgrade — the next decode rebuilds them at the new key. No user action needed; the cost is one cache miss per asset on the first run.

Supply-chain checks were soft-fail

cargo audit and cargo deny check carried continue-on-error: true in CI from the days when the exception policy was still being settled. Both now hard-fail. The exception policy lives in docs/threat-model.md §“Supply chain”:

  • Advisories without an upstream fix land in deny.toml (advisories.ignore) with a comment naming the upstream tracking issue and the runtime-exposure rationale.
  • cargo audit also takes inline --ignore RUSTSEC-XXXX-XXXX flags in .github/workflows/ci.yml; same documentation rule.
  • Both exception lists are reviewed each minor release.

The existing ignore for RUSTSEC-2024-0436 (paste unmaintained, transitive through wgpu macOS metal + accesskit Windows AT bridge, no runtime path on Linux X11/Wayland) stays in place with the rationale documented inline.

What’s added in 0.5.5

Aggregate memory budget across the scene

MAX_DECODED_ASSET_BYTES = 512 MB × MAX_ENTITIES = 64 allowed a 32 GB worst case when a hostile config (or accidental mass-drop) loaded the maximum on every slot. A new aggregate cap defaults to 1 GB total across all loaded entities; Scene::add_entity_from_path and Scene::append_character_config reject loads that would push the running total above the cap and surface an error toast:

memory budget exceeded (820 MB used + 270 MB incoming > 1024 MB cap);
set ANIMA_MEMORY_BUDGET_MB to raise

Override at startup with ANIMA_MEMORY_BUDGET_MB=<int> (high-RAM machines that want headroom for many small assets, smoke tests that want a tighter cap, etc.). The variable is read once per push and validated for non-zero positive parses; anything malformed falls back to the default.

A new helper Scene::total_decoded_bytes() reports the current running total — useful for surfacing in the perf overlay later.

Documentation refresh

  • README declares Status: 0.5.4, all .deb / AppImage example commands use the matching filenames, and the Wayland section ships a canonical Feature × Backend table marking the X11/XWayland path as stable and the native Wayland path as opt-in beta with explicit notes about wlroots coverage and the GNOME/KDE XWayland fallback.
  • docs/architecture.md Native-Wayland status table now reflects E.1 (keyboard) / E.4 (drag-drop) / E.5 (egui events) shipping, and flips global hotkeys from ❌ to ⚠ via D-Bus + compositor binding with the rationale (Wayland refuses raw XGrabKey-style grabs).
  • New SECURITY.md documents the reporting channel (private GitHub advisory), the supported-version policy (latest minor only), the pointer to the threat model, and the disclosure timeline.
  • New ROADMAP.md enumerates shipped releases by theme (0.1 → 0.5.4), the in-flight 0.5.5 hardening, and the 0.6 candidates under consideration (renderer polish / portal hotkeys / plugin behaviors), plus an explicit non-goals list (macOS / FreeBSD ports, network features, bundled assets).

Tests

252 pass in the lib suite — 21 added this release: 4 cache-key fingerprint, 6 budget/decoded-bytes, 5 animation-tick walk (variable delays, resync after stall, fixed-FPS regression), 2 easing (non-negative intervals on every curve, BounceOut sum at awkward frame counts), 4 private-dir verification (fresh create, lax mode, symlink, wrong owner). cargo clippy --all-targets --all-features -- -D warnings clean. cargo fmt --all -- --check clean. cargo audit and cargo deny check green locally. 6 s live smoke test on XWayland with a 2-entity animated scene: clean start, paced rendering, clean exit.

Upgrade notes

Configs decode unchanged. Observable user-facing changes:

  • Idle CPU/GPU use drops to near zero when the scene is static; CPU use scales with sprite FPS instead of display refresh when only animations play. No configuration needed.
  • GIF/WebP assets with variable per-frame delays keep correct frame timing across stalls (they could drift or land on the wrong frame before).
  • The BounceOut easing now holds the configured loop duration exactly; if you tuned an entity’s FPS around the old (shorter) loop, it will play slightly slower — re-tune the FPS slider.
  • First launch rebuilds the on-disk asset cache (one decode per asset). Subsequent launches are unchanged.
  • Drag-drop / library “Add to scene” / preset Append refuse to add new entities when the aggregate decoded RGBA would exceed 1 GB (default). Set ANIMA_MEMORY_BUDGET_MB=2048 (or higher) to lift the cap when you have a large scene of small assets.
  • CI now blocks PRs on cargo audit / cargo deny findings. Contributors hitting one should either bump the offending dep or add an explicit ignore with the rationale, per docs/threat-model.md §“Supply chain”.
# Debian / Ubuntu
sudo apt install ./anima-engine_0.5.5-1_amd64.deb

# AppImage
chmod +x animaEngine-0.5.5-x86_64.AppImage
./animaEngine-0.5.5-x86_64.AppImage

Audit status post-0.5.5

All 0.5.0 audit findings closed in 0.5.1; 0.5.2 closed the M3/M4 sweep; 0.5.3 closed the second-round audit; 0.5.4 closed the post-refactor audit. 0.5.5 picks up the four external-review items (stale docs, soft-fail CI, cache key granularity, missing aggregate budget) plus the SECURITY.md / ROADMAP.md additions. The remaining LOW from 0.5.4 (KeyBindings.map per-action vector cap on deserialize) stays accepted under the same-user threat model; the informational items from earlier rounds (TOCTOU between pre_validate and decoder, egui TextEdit without focus restoration) remain documented invariants.

Files of 0.5.5 (2)

animaEngine 0.3.0 — engine polish (Faza C)

Release page

Faza C — ten sub-phases on top of 0.2.1. The renderer pipeline still draws the same way it did in 0.2; the engine got a wider model around it instead of a faster one. Where C.6, C.7, and C.8 had wider original scope, the deferred portions are documented in docs/engine-features.md with rationale, queued for 0.4.

Highlights

🖥 Multi-monitor distribution

Three modes, persisted in ~/.config/animaEngine/config.toml:

Mode Behaviour
PerMonitor (default for fresh installs) One overlay surface per detected monitor; entities resolve to their monitor via centroid hit-test
Span Single overlay across the primary monitor — the 0.2 behaviour
Single { name } Overlay only on the named monitor (useful for streaming setups)

Per-entity pin (monitor: Option<String> in the character config) keeps a specific entity on a specific output. Ctrl+M cycles the selected entity through every available monitor and emits a localised toast on each step. Stale pins fall back to centroid resolution with a warning in the log.

Render-side multi-monitor dispatch (one winit::Window per output) is deferred to 0.4 with the multi-window event-loop refactor; the data layer + UI ship now.

📚 Asset library

Drop your characters under ~/.local/share/animaEngine/assets/ (override with $ANIMA_ASSETS_DIR) and animaEngine indexes them on startup into ~/.local/share/animaEngine/library.toml. The new Library tab in the settings sidebar surfaces the index with a search bar, per-row kind icon, and a one-click “Add to scene” button.

Critical invariant preserved: every “Add to scene” goes through Scene::add_entity_from_path — the same path drag-drop uses. The extension whitelist, byte caps, and frame caps still apply (a unit test asserts the two whitelists stay aligned, preserving audit invariant L2).

Library merge-scan is non-destructive: tags + last-used-at survive between scans, and disconnected drives don’t drop indexed entries. Thumbnails render typed Phosphor icons in 0.3; real decode lands in a follow-up patch when there’s actually a use case for it.

🎯 Bounce behavior

[characters.behavior]
type = "bounce"
amplitude_px = 24.0
period_sec = 1.5
axis = "vertical"  # or "horizontal", or "both" for a circular Lissajous

Sinusoidal oscillation around the entity’s stored position. The rest position locks in on the first tick and re-locks on drag, arrow-key nudge, and Home-center, so the sprite never snaps back to a stale centre. Period clamped at ≥ 50 ms; gravity wins when both Bounce and physics_enabled are on.

Spinner and Reactive variants from the original spec are deferred to 0.4 — rationale in docs/engine-features.md §4.1 and §4.3.

🌊 Animation curves

Six options on the per-frame timing pipeline:

Curve Feel
Linear 0.2 behaviour — every frame held for 1/fps seconds
EaseInQuad Slow start, fast finish
EaseOutQuad Fast start, gentle finish
EaseInOutQuad Slow at both ends, fast middle
Sine Sinusoidal ease, softer than the quads
BounceOut Overshoots near t=1 then settles

Distorts the interval between frames while preserving the loop’s total duration exactly — easings.net BounceOut hits f(1) = 1 to the machine epsilon. GIF and WebP per-frame delays remain authoritative when present; easing is a no-op for those formats.

👯 Sprite groups

Bind multiple entities into one named group with a per-group visibility flag:

[[groups]]
id = "halloween"
name = "Halloween Squad"
member_ids = ["ghost_1", "ghost_2", "ghost_3"]
visible = true

When visible = false, the group’s members don’t render and can’t catch clicks — both Scene::visible_entities and Scene::entity_at_point honour the composition. Removing an entity scrubs its id from every group (dangling-membership invariant enforced by tests). Offset / scale composition into the renderer + inline group editing in the UI are deferred to 0.4; the read-only section in the Scene tab surfaces existing groups for now.

⚡ Performance baseline

cargo run --example perf_baseline --release measures the engine’s hot loop without any I/O or GPU work:

entities    tick avg  visible avg    tick+vis
----------------------------------------------
      10     0.000 ms     0.000 ms     0.000 ms
      25     0.001 ms     0.000 ms     0.001 ms
      50     0.002 ms     0.000 ms     0.002 ms
     100     0.004 ms     0.000 ms     0.004 ms

The 60 fps frame budget is 16.6 ms; the docs/engine-features.md target was < 8 ms at 100 entities. On the dev box we land at 0.004 ms — over 2000× under target. Whatever budget your overlay has, the engine isn’t eating it.

Other changes

  • Animation::easing: Option<EasingCurve> round-trips through TOML via a new optional field on CharacterConfig
  • App::ctrl_held tracks Ctrl state alongside shift_held
  • Settings sidebar now has four tabs (Inspector / Scene / Library / Appearance) — previously three
  • src/anim.rs graduated from src/ui/anim.rs; usable by the animation pipeline and the UI alike
  • examples/perf_baseline.rs lands as a long-lived measurement artefact — no criterion dep, no CI gate, just a stable number to compare against
  • 36 new i18n keys land across all ten locales; the parity test still passes

Tests

211 total (up from 195 in 0.2.1). New coverage:

  • Monitor topology resolution (centroid, explicit pin, stale-pin fallback, off-screen, no-monitors, no-primary)
  • Library extension whitelist matches drag-drop whitelist
  • FNV-1a id stability + avalanche
  • TOML round-trip for WindowConfig, LibraryAsset, GroupConfig
  • Bounce: rest snapshot, quarter-period peak, axis isolation, circular trace under Both, invalidate semantics, period clamp
  • EasingCurve: every curve hits f(0)=0 and f(1)=1, EaseInOutQuad symmetry, BounceOut endpoints, intervals-sum-to- total-duration under every curve
  • Group composition: AND of member ∧ group visibility, hit-test skip, cleanup on entity removal, duplicate id detection

Installing

Debian / Ubuntu (.deb)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.3.0/anima-engine_0.3.0-1_amd64.deb
sudo apt install ./anima-engine_0.3.0-1_amd64.deb

AppImage (any distro)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.3.0/animaEngine-0.3.0-x86_64.AppImage
chmod +x animaEngine-0.3.0-x86_64.AppImage
./animaEngine-0.3.0-x86_64.AppImage

From source

git clone https://github.com/Alexandru2984/animaEngine
cd animaEngine
git checkout v0.3.0
sudo apt install -y build-essential cmake libvulkan-dev \
    libx11-dev libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev \
    libwayland-dev libxrandr-dev
cargo build --release
./target/release/anima_engine

Verifying the build

SHA-256 checksums:

cfad0fdc11c4db8ccb0f83bf46dd3894e0190ad25e421b6f7524dc178e9109bc  anima-engine_0.3.0-1_amd64.deb
00b0fb27aaa9c97a339d83345a4aa8ff27adcb1170d60a117779c323a4da6508  animaEngine-0.3.0-x86_64.AppImage

The .deb is byte-reproducible on the same Rust toolchain (libxkbcommon-x11-0 declared in Depends, libgl1 + libvulkan1 already there). The AppImage bundles libxkbcommon-x11.so.0 so it runs on minimal distros; reproducibility envelope same as 0.2.1 (use the container under packaging/Dockerfile.appimage-builder).

sha256sum -c SHA256SUMS-v0.3.0.txt
dpkg-deb --field anima-engine_0.3.0-1_amd64.deb Depends

Upgrading from 0.2.x

All config fields added in 0.3 (monitor_mode, monitor, easing, groups, windows) are optional or carry sensible defaults. A 0.2.x config.toml decodes byte-identical and behaves byte-identical unless you opt in to a new feature from the UI.

Notable defaults that change shape across the boundary:

  • Fresh installs in 0.3 default to MonitorMode::PerMonitor. A 0.2 user with a single monitor sees no behavioural difference; a 0.2 user with multiple monitors who hand-stretched the overlay across them with Span should set [global] monitor_mode.kind = "span" explicitly.
  • Library tab scans ~/.local/share/animaEngine/assets/ at startup. If the directory doesn’t exist, the tab shows an empty state explaining where to put files — no error.

What’s next

  • 0.4 / Faza D — UX completion: rebindable keymap, collapse- state persistence, runtime AccessKit toggle, error states cabled, perf overlay, onboarding 2.0, multi-window event-loop refactor, render-side multi-monitor dispatch, group offset/scale composition, Spinner + Reactive behaviors, real thumbnail decode in the Library tab
  • 0.5 / Faza E — Platform reach: Wayland native completion, macOS port, FreeBSD support, fuzzing harness
Files of 0.3.0 (2)

animaEngine 0.2.1 — startup-crash patch

Release page

Patch release for a single nasty bug: 0.2.0 crashed on startup on distros that don’t ship libxkbcommon-x11 preinstalled. If your 0.2.0 install works, you don’t need this update. If it died with

Library libxkbcommon-x11.so could not be loaded.

— this is the fix.

What went wrong

In 0.2.0 we turned on the AccessKit feature for egui-winit so screen readers on Linux could see the UI. AccessKit on Linux uses accesskit_unix, which dlopens libxkbcommon-x11.so.0 at runtime rather than linking it through ELF NEEDED tags.

Three downstream consequences slipped through:

  • linuxdeploy couldn’t see the dependency when packing the AppImage (it walks NEEDED tags, not dlopen calls)
  • cargo-deb’s $auto reads the same NEEDED tags, so the .deb didn’t declare a dependency either
  • The CI smoke test runs on a minimal Ubuntu image that doesn’t pull libxkbcommon-x11 through any other package, so it crashed the same way

Three independent fixes, one root cause.

Fixes in this release

Surface Fix
AppImage scripts/build-appimage.sh now resolves libxkbcommon-x11.so.0 via ldconfig on the build host and passes it through --library to linuxdeploy. The library is bundled inside the AppImage.
.deb [package.metadata.deb] depends now explicitly lists libxkbcommon-x11-0, so apt install pulls it in on fresh systems.
CI All four jobs that compile Rust (clippy, test, build, smoke) now install libxkbcommon-x11-dev alongside the existing system deps.

Installing

Debian / Ubuntu (.deb)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.2.1/anima-engine_0.2.1-1_amd64.deb
sudo apt install ./anima-engine_0.2.1-1_amd64.deb

AppImage (any distro)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.2.1/animaEngine-0.2.1-x86_64.AppImage
chmod +x animaEngine-0.2.1-x86_64.AppImage
./animaEngine-0.2.1-x86_64.AppImage

Upgrading from 0.2.0

No config migration needed — ~/.config/animaEngine/config.toml is read by both versions unchanged.

If you installed 0.2.0 via .deb:

sudo apt install ./anima-engine_0.2.1-1_amd64.deb

If you ran 0.2.0 via AppImage, just replace the binary.

If you built 0.2.0 from source on a machine that already had libxkbcommon-x11-0 installed, you don’t have to do anything — the 0.2.0 binary worked for you. But pulling the patch keeps your CI green next time you push.

Verifying the build

SHA-256 checksums:

4ebc892578fc79bbe5187e472c3c71b0330c766174d9e043654dcc5cd5e589ad  anima-engine_0.2.1-1_amd64.deb
1e283bdeacdd574ec4bdddcc3ed1a6aa21394942668aa8c44f49b8a3dc1a8821  animaEngine-0.2.1-x86_64.AppImage

.deb depends on libxkbcommon-x11-0 explicitly now (verifiable with dpkg-deb --field anima-engine_0.2.1-1_amd64.deb Depends).

AppImage bundles libxkbcommon-x11.so.0 directly (verifiable by running ./animaEngine-0.2.1-x86_64.AppImage --appimage-extract 'usr/lib/libxkbcommon*').

Security hardening (from the post-Faza A audit)

This release also folds in four small hardening items from the external security audit run against 0.2.0 + the 0.2.1 packaging fix. None of these were release blockers; they’re documented + fixed now because the audit pass is fresh.

  • AT-SPI exposure documented in docs/threat-model.md §9. The AccessKit bridge enabled in 0.2.0 publishes every egui widget label (including the Ctrl+K palette query as you type) on the session bus. Same-UID processes were already inside the trust boundary, but the what wasn’t visible — now it is. Opt-out path noted for operators who don’t need a screen reader.
  • Locale rejection now logs warn! in i18n::init and i18n::set_locale. A hand-edited config.toml with locale = "../etc/passwd" previously fell back silently to English; now it leaves a tracing line so tampering is visible.
  • SECURITY: comment on Scene::reset_to_configs / append_character_config. These methods load CharacterConfig::asset_path without re-running drag-drop validation, because today every caller passes a hardcoded preset. The comment makes the invariant explicit so future contributors routing user input through these methods know to add the pre-validation back.
  • AppImage reproducibility envelope documented + a pinned build container shipped at packaging/Dockerfile.appimage-builder. The .deb is byte-reproducible; the AppImage is byte-reproducible only when built inside the container (bundled libxkbcommon-x11’s hash is tied to the build host). Maintainers reproducing locally on a different distro should expect a different SHA256 unless they use the container.

The audit found 0 critical, 0 high findings against the new 0.2.0 + 0.2.1 surface. Baseline B.1-B.5 hardening (atomic writes, asset caps, drag-drop validation, single-method D-Bus invariant, license allowlist) was verified intact, no regressions.

Not changed

Everything user-facing in 0.2.0 carries over unchanged: themes, tabbed sidebar, presets, command palette, ten locales, AccessKit bridge.

Files of 0.2.1 (2)

animaEngine 0.2.0 — UI/UX polish

Release page

A twelve-step coherence pass on top of 0.1. The engine renders the same content; the chrome around it is a different product.

TL;DR

Themes (4 of them, including high-contrast AAA), a tabbed settings sidebar with collapsible inspector, a Ctrl+K command palette, six bundled scene presets, ten UI languages, and an AccessKit screen-reader bridge — all without leaving Rust, all under 9 MB on disk.

Highlights

🎨 Four themes

Dark and Light by default, plus two high-contrast siblings tuned to WCAG AAA (≥ 7:1 text contrast, 3 px focus ring, zero animation time for motion-sensitive users). Switch in Appearance → Theme — every panel re-renders instantly, no restart, no flicker.

CI now refuses any colour change that drops the palette below its threshold. Coherence is enforced, not hoped for.

🧭 Redesigned settings sidebar

Three tabs replace the long scroll:

  • Inspector — entity-specific controls in collapsible sections (Position / Appearance / Animation / Behavior) with the most-used quick-toggles pinned at top (Visible, Gravity)
  • Scene — entity list with a pulsing accent stripe on the selected row, plus the new preset gallery
  • Appearance — theme picker, language picker, and a read-only keyboard reference table covering all 21 actions

A sticky header carries the app icon, a sticky footer shows the live entity count.

🚀 Ctrl+K command palette

A fuzzy-search popup centered near the top of the screen. Type “halloween” to find a preset; type “light” to switch themes; press Enter / click to execute. Closes on Esc or another Ctrl+K.

📚 Six bundled scene presets

One-click starting points using only the shipped demo assets — no external paths, never fails out of the box:

Preset Vibe
Cozy Companion One gentle ghost wandering on the right edge
Productivity Zen Static slime + heart at low opacity in a corner
Halloween Party Three ghosts marching with mismatched speeds
Birthday Confetti Hearts and stars raining down with gravity
Studio Session All five demo characters with mixed behaviours
Cursor Follower A cat that tags along with the mouse

Each preset can Append (suffixes IDs so nothing collides) or Replace (wipes the current scene first, styled destructive so the choice feels deliberate).

🌍 Ten UI locales

English, Română, Español, Deutsch, Français, Italiano, Português (BR), Polski, Nederlands, 日本語. The active locale auto- detects from LANG / LC_ALL / LC_MESSAGES on startup; an explicit override in Appearance → Language persists across restarts. Backed by Project Fluent, English fallback at every lookup so a missing translation never produces an empty label.

The language picker lists autonyms — your language in its own script — so you can find yours without reading English first.

♿ Accessibility commitments

  • AccessKit + AT-SPI bridge enabled by default — Orca, Speakup, and other Linux ATs read every egui widget without further setup
  • High-contrast theme variants clear WCAG AAA on every text tier
  • Visible focus rings (2 px on standard themes, 3 px on HC) on every interactive widget
  • Read-only keyboard reference table documents all 21 actions in one place

Full commitments + deliberate non-goals in docs/accessibility.md.

👻 New app icon

The “Ghost Mascot” — a friendly white ghost on a violet gradient with motion-dot trails. Chosen from three exploratory variants kept in the repo for future reference. Replaces the previous “a” mark across the desktop file / hicolor theme.

Other changes

  • Toast notifications redesigned per the design system: bg.elevated surface, semantic-coloured severity icons (CheckCircle, Warning, XCircle, Info), slide-in fade-out animation timed off the toast’s age
  • Three dismissible inline onboarding hints for fresh users (tabs, V/G shortcuts, theme instant-apply). Existing users skip everything via #[serde(default = "OnboardingProgress::all_seen")]
  • Settings sidebar default width: 280 → 320 px
  • Phosphor icon font wired through src/ui/icons.rs — every glyph in the UI is now a named constant

Tests

119 tests pass (up from 90 in 0.1.0). New coverage:

  • WCAG contrast assertions on every theme variant
  • FTL syntax + key-coverage parity across all ten locales
  • Preset roster shape (non-empty, under cap, unique IDs, demo-asset-only)
  • Action enum metadata completeness
  • Toast / spinner timing-curve helpers
  • Onboarding serde upgrade paths

Installing

Debian / Ubuntu (.deb)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.2.0/anima-engine_0.2.0-1_amd64.deb
sudo apt install ./anima-engine_0.2.0-1_amd64.deb

AppImage (any distro)

wget https://github.com/Alexandru2984/animaEngine/releases/download/v0.2.0/animaEngine-0.2.0-x86_64.AppImage
chmod +x animaEngine-0.2.0-x86_64.AppImage
./animaEngine-0.2.0-x86_64.AppImage

From source

git clone https://github.com/Alexandru2984/animaEngine
cd animaEngine
git checkout v0.2.0
sudo apt install -y build-essential cmake libvulkan-dev \
    libx11-dev libxcb1-dev libxkbcommon-dev libwayland-dev libxrandr-dev
cargo build --release
./target/release/anima_engine

Verifying the build

SHA-256 checksums:

f60e611a411ad8da95cf1c3f15699f0d813f77b941ea48ca57fb0c7278eabccb  anima-engine_0.2.0-1_amd64.deb
cb1c0fa7d73239eb649efda988a42cb8245cf38525270484d64e177fa649422c  animaEngine-0.2.0-x86_64.AppImage
# .deb integrity + checksum
sha256sum -c SHA256SUMS-v0.2.0.txt
dpkg-deb --info anima-engine_0.2.0-1_amd64.deb
dpkg-deb --contents anima-engine_0.2.0-1_amd64.deb

Reproducing the build locally:

make deb        # produces build/anima-engine_0.2.0-1_amd64.deb
make appimage   # produces build/animaEngine-0.2.0-x86_64.AppImage

Known issues

  • paste crate flagged as unmaintained (RUSTSEC-2024-0436). Pulled in transitively by wgpu-hal (macOS metal backend) and accesskit_winit (Windows AT-SPI bridge). Neither path executes on the Linux X11 / Wayland targets we ship for, so no runtime exposure. Will land an upstream fix in a follow-up.
  • Romanian translations are native-quality; the other nine locales are best-effort technical translations awaiting native review. Pull requests against src/i18n/locales/*.ftl very welcome.

Upgrading from 0.1

Configs round-trip cleanly. The new fields (theme, locale, onboarding) all carry #[serde(default = ...)] annotations tuned so that upgrading users:

  • Keep their existing scene as-is
  • Default to Dark theme (matching 0.1’s behaviour)
  • Default to environment locale (no UI change unless LANG is non-English)
  • Skip every onboarding hint (those are only for fresh installs)

Nothing in ~/.config/animaEngine/ needs manual editing.

What’s next

  • 0.2.x patch series for translation fixes from native speakers
  • 0.3 plan: user-rebindable keyboard map; persistence for collapse-state per inspector section; multi-window for multi- monitor setups; opt-in sound on toast severity
Files of 0.2.0 (2)

Tagged without a release page

These versions were tagged in the repository but have no GitHub release with files. Their notes are in the repository.

Release data last synced from GitHub on . For anything newer, see GitHub Releases.