# Sprite Studio rigs sprites in Rust instead of regenerating them

> sprite-maker is a Tauri desktop workbench for 2D game art that pairs per chat AI image generation with a native Rust rig renderer producing identical bytes from the same bones. The catch is that releases are built per platform on a native host, and the AI half depends on an agent CLI you install yourself.

**JohnKinyanjui/sprite-maker** — An open source ai sprite maker

- Repository: https://github.com/JohnKinyanjui/sprite-maker
- Stars: 414 · Forks: 53
- Language: Rust
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/johnkinyanjui-sprite-maker

## The rig renderer produces bytes, not images

The distinguishing claim in this project is that rigging is not a second round of image generation. The rig engine is written natively in Rust and runs on the local machine. Per frame bone rotations, scales, offsets, root motion, holds and z-layering compose through parent chains and render with nearest-neighbor inverse mapping, so identical inputs always produce identical PNG bytes. Nothing calls a model during that step.

That has two consequences worth stating plainly. First, cost: the project advises defaulting to the native rig, since `/animate` with the rig renderer is deterministic and free per frame, and treating AI polish as something you opt into only when a frame actually needs it. Second, reproducibility: a rig you approved in August still renders the same walk cycle after the model behind it has changed.

Rendered frames are not quarantined. They land in `assets/<category>/`, become normal assets, form an animation with quality analysis attached, and then flow into sheets, the playground and exports exactly like an AI generated sprite would. The rendering side lives under `src-tauri/`, with the Svelte front end in `src/`.

## Points and capsules replace hand-painted masks

A rig here is a set of named points and the capsule bones between them. The point names are fixed: `joint`, `anchor`, `contact` and `pivot`. The engine auto-claims every opaque pixel inside the closest capsule and assigns whatever is left over to the nearest bone, which removes the usual step of painting a mask by hand for each new sprite.

Points can arrive three ways. The Rig editor auto-places them from an anatomy template, the AI can suggest them, or you drag them yourself. The last route matters more than it sounds, because a suggestion is only a starting position and a capsule is easy to nudge once you can see which pixels it swallowed.

Contacts are what stop a cycle from sliding. Feet and hands stay pinned in place while the chain bends around them using analytic two-bone IK, so a walk cycle holds its ground line instead of drifting. The same idea extends past humanoids: the centipede harness accounts for morphology that a human walk template cannot handle, using a phase-shifted head-to-tail body wave, alternating leg banks, a stable ground line and twelve distinct crawl frames at 12 FPS. The motion planner estimates a physical envelope unless you supply an exact speed, height or scale.

## Ask AI hands your sprite to a CLI you installed

The AI half is delegated, not embedded. Sprite Studio is built with Tauri, Svelte, Rust and SQLite, together with an installed Codex, Cursor or Antigravity CLI. When you press `Ask AI`, the sprite goes to that agent CLI and comes back as a `rig-suggestion` JSON block containing points, bones and optional pose frames, each with confidence values. Typing `/rig` in chat does the same thing, and the captured rig appears in the Rig tab on its own.

Reading the result as structured JSON with per element confidence is the useful part. You can accept the whole block, edit it, or discard it and fall back to the anatomy template, and the Rig editor shows the capsules either way.

The practical dependency is explicit: the app expects one of those three CLIs to be present on the machine, and the quality of a suggestion is bounded by whichever one is configured. The deterministic path has no such dependency. Rigger in the Rig editor with template or manual points and the work proceeds with the AI absent.

## The anchor contract decides whether an export is usable

Generating one attractive image is the easy part, and the project is organised around the parts that are not. A production asset needs a stable identity, clean transparency, readable scale, a consistent palette, a useful file structure and, when it moves, a mechanically complete loop. Each of those has a specific mechanism attached.

The anchor is the mechanism for identity. The recommended order is one master, then motion: approve a character master, promote it as the anchor, then animate or import a strip. Frames are normalized to the anchor contract, alignment metadata is nudged in the aligner, the animation is accepted, and only then does the export run. Skipping the accept step is how sheets end up with mismatched canvas sizes.

Structure is handled so it does not fight you. Every chat keeps its own style, references, quality, dimensions, frame policy, FPS, model and reasoning settings, so experimenting in one conversation does not silently change the defaults of another. Related animation frames are grouped as one playable sprite set instead of flooding the library, and the export writes a PNG sheet plus metadata while keeping the source files and the conversation that produced them.

## Motion planning treats loop closure as part of the plan

The AI animation path is sequential, not one-shot. Asking to animate something brings the source asset back into chat and requests a description of how it should move, with suggestions drawn from the visible anatomy. The model then plans the complete motion once and generates one frame at a time, using the source identity and the frames already accepted next to it. The default range of 24 to 48 frames favours smooth motion, and you can lower it at any point; the frame policy stays on Auto unless you need an exact count.

The worked examples in the guide describe specific mechanics rather than vague motion. The rabbit is an eight-pose hop cycle that compresses the haunch, pushes from the hind leg, tucks in the air, reaches with the forefeet, absorbs contact and recovers into the opening stance. The dragon is a twelve-frame wingbeat in which the same identity survives a forceful downstroke, a folded recovery, a body lift, delayed legs and a tail counterbalance.

One caveat on the guide text: the paragraph introducing loop closure ends mid-sentence in the copy this article is built from, so the closing rule itself is not something to quote. For locomotion the advice is concrete anyway: one horizontal AI strip beats eight independent frames, and you split, normalize and align it in the Animate tab.

## Each installer has to be built on its own native host

The Makefile treats releases as a per platform job, and its help text says so directly. The default goal is `help`, and the release path runs verify, build and collect for the machine it is on:

```bash
make install
make verify
make fetch-ffmpeg
make bundle
make release
```

`make install` installs locked JavaScript dependencies against the committed `bun.lock`, `make verify` runs the frontend and Rust checks, and `make fetch-ffmpeg` downloads the ffmpeg binary bundled for your platform, which is a separate download you have to trigger. The collected artifacts land under `release-artifacts/<version>/<platform>`, with the version read out of `package.json`.

macOS gets special treatment. `make release-macos` builds one universal Intel plus Apple Silicon binary against the `universal-apple-darwin` target, and `make publish-macos` builds on macOS and uploads to a tag that defaults to the version prefixed with `v`:

```bash
make release-macos
make publish-macos
```

The host check is explicit. `uname -s` maps Darwin to macOS, Linux to Linux and an MINGW, MSYS or CYGWIN prefix to Windows, and anything else stops the build with an unsupported host error telling you to build releases on macOS, Windows or Linux.

## bun runs the front end, make verify runs the Rust side

Development splits cleanly along the two stacks. The JavaScript side is driven by package.json scripts, and bun is the package manager, with `bun.lock` and `bun-types` in the tree and `bun test` as the test entry:

```bash
bun install
bun test
bun run check
bun run dev
bun run tauri
```

`bun run check` runs `svelte-kit sync` and then `svelte-check` against the project tsconfig, `bun run dev` starts the Vite dev server, and `bun run tauri` hands off to the Tauri CLI that drives the desktop shell. The Rust checks and the native tests are reached through the Makefile instead, which is why `make verify` exists next to these.

The stack behind those scripts is Svelte 5 on SvelteKit with Vite 8 and the static adapter, TypeScript around 6.0, and Tauri 2 for the desktop layer. Runtime dependencies are small and mostly boundary code: the Tauri API with its dialog and opener plugins, an Iconify Lucide icon set, `marked` for markdown and `dompurify` for sanitising markup, both of which sit in the same dependency list as the chat surface that renders model output. Governance, contribution and changelog files sit at the repository root beside an MIT licence.

## Desktop only, and the model lives outside the app

Two scope limits are stated rather than implied. The platforms listed are macOS, Windows and Linux, and the project says plainly that it does not target Android or iOS. There is also no built-in model account. Because the agent CLI is an external program, local-first means your conversation history and your assets stay in the app's SQLite store on your machine, while the generation step still goes wherever that CLI is configured to send it.

Documentation ships twice over. There is an English guide at `docs/en/user-guide.md` and an Italian one at `docs/it/guida-utente.md`, an index at `docs/README.md`, and the same content is available inside the app through Guide in the left sidebar with an EN or IT toggle.

On maintenance: the repository is not archived and the last push was on 2026-09-24, the same day v0.3.3 was tagged, with v0.3.2 and v0.3.1 both landing on 2026-08-19. The package manifest reads 0.3.3 and is MIT licensed, so there is nothing in the licensing that constrains a commercial game built with the output.

## Conclusion

sprite-maker suits a solo 2D artist or a small team that wants its own AI credentials and its own files rather than a hosted sprite tool, and the rig renderer is the reason to try it: bone work costs nothing per frame and repeats exactly. Skip it if you need Android or iOS output, because the project states it does not target either, or if you cannot install a Codex, Cursor or Antigravity CLI, since that is where the AI half of the workflow lives. Check three things first: that `make verify` passes on your machine, that the per chat settings are the ones you want, since style, references, quality, dimensions, frame policy, FPS, model and reasoning are stored per conversation, and that your license terms accept the MIT grant. The last push was on 2026-09-24 and v0.3.3 shipped the same day, so the cadence is active; the practical limit is that each platform installer has to be built on that platform's own host.

## FAQ

### Does Sprite Studio need its own AI account or API key?

The project is built on Tauri, Svelte, Rust and SQLite alongside an installed Codex, Cursor or Antigravity CLI. `Ask AI` sends the sprite to that CLI and reads back a `rig-suggestion` JSON block of points, bones and optional pose frames with confidence values, so the model configuration lives in the CLI rather than in the app.

### How is Sprite Studio's rig renderer different from generating frames with AI?

The rig is native Rust: bones derive their pixels from capsules, planted contacts are solved with analytic two-bone IK, and identical inputs render identical PNG bytes with no image generation at all. The project recommends defaulting to `/animate` with that renderer because it is deterministic and free per frame, and adding AI polish only when a frame needs it.

### How many frames does a Sprite Studio AI animation produce by default?

The default range is 24 to 48 frames, which favours smooth motion, and it can be lowered at any time. The frame policy stays on Auto unless you need an exact count, and frames are generated one at a time from the source identity plus the neighbouring frames already accepted.

### What are the named points in a sprite-maker rig?

There are four: `joint`, `anchor`, `contact` and `pivot`, connected by capsule bones. The engine auto-claims every opaque pixel inside the closest capsule and gives leftovers to the nearest bone, so no mask painting is required. Points can come from an anatomy template, from the AI, or from dragging them yourself.

### How do I build and publish a sprite-maker release?

Use the Makefile targets on the platform you are targeting: `make release` verifies, builds and collects installers for the current machine, `make release-macos` produces a universal Intel and Apple Silicon build, and `make publish-macos` uploads to a tag defaulting to `v` plus the package.json version. Artifacts are collected under `release-artifacts/<version>/<platform>`.

## Sources

- [Issues](https://github.com/JohnKinyanjui/sprite-maker/issues)
- [JohnKinyanjui/sprite-maker on GitHub](https://github.com/JohnKinyanjui/sprite-maker)
- [License: MIT](https://github.com/JohnKinyanjui/sprite-maker/blob/main/LICENSE)
- [README](https://github.com/JohnKinyanjui/sprite-maker/blob/main/README.md)
- [Releases](https://github.com/JohnKinyanjui/sprite-maker/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/johnkinyanjui-sprite-maker
