Skip to content

animaEngine 0.3.0 — engine polish (Faza C)

Choose a tag to compare

@Alexandru2984 Alexandru2984 released this 03 Jun 20:40
· 674 commits to main since this release

animaEngine 0.3.0 — engine polish

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