8000 GitHub - umamoorg/umamo: Umamo is an open-source cross-platform rigging editor for 2D puppet animation, with first class pen and touch support, built as a drop-in replacement for the Live2D Cubism Editor. · GitHub
[go: up one dir, main page]

Skip to content
umamoorgPublic

About

Umamo is an open-source cross-platform rigging editor for 2D puppet animation, with first class pen and touch support, built as a drop-in replacement for the Live2D Cubism Editor.

Topics

Resources

Stars

191 stars

Watchers

6 watching

Forks

Repository files navigation

Umamo

An open-source cross-platform modelling editor for 2D puppet animation, with first class pen and touch support, designed to interoperate with the Live2D Cubism source format (.cmo3). Runs on Windows, macOS, Linux, and Android tablets with pen/touch input. Supports importing and exporting both CMO3 and MOC3 formats.

Status: Early development. Prebuilt downloads are on the Releases page.

Screenshot showing the main Umamo window with 2D puppet posed and smiling in a centered viewport.  The left side shows an adjustable parameter panel while the right shows an object outliner, information, and history panel.

Quick Notes

Q: Can I support the Umamo project financially?

A: Umamo is completely open source and free, but if you would like to support the project you can join the Patreon or make a one time donation through Ko-Fi. All received funds go directly to paying hosting bills, hardware for testing, and platform developer fees. Excess funds will be banked for the future or distributed to other open source projects working with the Umamo Project.


Q: Does Umamo do animations yet?

A: Not yet. This is a long term stretch goal. Getting the modeling, UV editor, and physics interface perfected first will be important for animation later.


Q: Umamo doesn't support a newer version of Cubism/Krita/Clip Studio Paint file formats yet. Can you add support?

A: Yes, please search if the issue has already been reported and if not, open a new issue that describes the problem.


Q: Umamo corrupted my project and I lost my work! HELP!

A: Currently Umamo is alpha level software available for testing. Please make sure to make regular backups of your files. In fact, make second copies of your files explicitly for playing around with. Do not use the original copies.

Downloads

Every tagged version publishes desktop builds on the Releases page. There are two different releases per platform:

File Note
umamo-windows-x64-<version>.msi Windows installer. Installs for your user alone, with no administrator rights needed.
umamo-macos-arm64-<version>.dmg Apple silicon Macs. Open it and drag Umamo to Applications.
umamo-linux-<arch>-<version>.deb Debian 12+, Ubuntu 22.04+, Linux Mint 21+.
umamo-linux-<arch>-<version>.rpm Fedora and other RPM distributions.
umamo-<target>-<version>.zip/.tar.gz Java SDK not required, just unpack it and run it directly.
umamo-<target>-<version>.jar You will need Java SDK 21 or higher to run. When Java's default would give Umamo less than 3 GB of memory, it restarts itself with room for up to half of your computer's memory. To always allow half, start it from a terminal: java -XX:MaxRAMPercentage=50 -jar umamo-<target>-<version>.jar.

Targets: linux-x64, linux-arm64, windows-x64, macos-arm64, macos-x64. Check your download against the release's signed SHA256SUMS.txt (see Verifying downloads).

Signing. The MacOS downloads are signed and notarized by Apple, and the Linux RPM and the release's checksums are signed with the Umamo release key. Windows builds are not signed yet due to the high cost.

  • Windows: SmartScreen might show "Windows protected your PC" for the installer and the archive version's Umamo.exe. Choose More info -> Run anyway.

Installing

  • Windows:
    • Run umamo-windows-x64-<version>.msi.
      • Umamo installs per user to: %LOCALAPPDATA%\Programs\umamo,
        • A start menu entry will be added and *.uma files will be associated automatically.
        • Note: There is no confirmation screen, when the installer finishes it will exit without confirming.
      • Uninstall through Windows Settings -> Apps.
      • The zip archive version is portable and can be run directly after extracting: Umamo\Umamo.exe.
  • Debian, Ubuntu, Linux Mint:
    • sudo apt install ./umamo-linux-<arch>-<version>.deb.
      • Uninstall: sudo apt remove umamo.
  • Fedora: Import the Umamo release key once:
    • sudo rpm --import https://umamo.org/keys/umamo-signing-key.asc
    • sudo dnf install --setopt=localpkg_gpgcheck=1 ./umamo-linux-x64-<version>.rpm.
      • Uninstall: sudo dnf remove umamo.
  • Other Linux: tar xzf umamo-linux-x64-<version>.tar.gz and run umamo/bin/umamo.
  • MacOS: Open umamo-macos-arm64-<version>.dmg and drag Umamo to Applications, or unzip Umamo.app and move it there.

The DEB and RPM install Umamo to /opt/umamo, add it to the application menu, and make it the app that opens .uma files. If you registered the tarball's umamo.desktop by hand before, remove that first (below), or the menu will show Umamo twice.

To upgrade, install the new version over the old one. Your customized settings will be kept on upgrade and uninstall. If you need to reset your settings, then delete settings.json from:

  • Linux: ~/.config/umamo
  • MacOS: ~/Library/Application Support/umamo
  • Windows: %APPDATA%\umamo

Verifying downloads

The Umamo release key signs the RPM and every release's SHA256SUMS.txt. Its fingerprint is 67754C0DC58743270D574066F5499AE5C80A0F1C; the key is on umamo.org and in this repository at app/desktop/packaging/umamo-signing-key.asc. Download SHA256SUMS.txt and SHA256SUMS.txt.asc beside your files, then:

gpg --fetch-keys https://umamo.org/keys/umamo-signing-key.asc
gpg --verify SHA256SUMS.txt.asc SHA256SUMS.txt
sha256sum --check --ignore-missing SHA256SUMS.txt

gpg --verify names the key it checked; compare its fingerprint with the one above. Every file also carries a build provenance attestation from GitHub: gh attestation verify <file> --repo umamoorg/umamo confirms it was built by this repository's release workflow.

Opening .uma files from the file manager

The installers register the .uma type, and on MacOS Umamo.app declares it itself, so Finder can open .uma files with it. The portable zip and tarball register nothing on their own.

  • Linux: The archives come with freedesktop.org files to register the mimetype manually. Put umamo/bin/umamo on your PATH(or edit the Exec= line in umamo.desktop to its full path), then register them for your user:
xdg-mime install --novendor umamo/lib/app/resources/umamo-uma.xml
xdg-desktop-menu install --novendor umamo/lib/app/resources/umamo.desktop

xdg-mime uninstall and xdg-desktop-menu uninstall with the same files to undo it.

Log files

Go to Help -> Open Log Folder to open the log folder location. When submitting bug reports, please attach the newest file. Log file locations:

  • Linux: ~/.local/share/umamo/logs (or $XDG_DATA_HOME/umamo/logs)
  • MacOS: ~/Library/Application Support/umamo/logs
  • Windows: %LOCALAPPDATA%\umamo\logs

Building & Development

Umamo is a Kotlin Multiplatform project (Gradle, Kotlin DSL) targeting desktop and Android from one shared codebase.

Platform Note
Windows Regularly built and tested
Linux Regularly built and tested
MacOS Working, minimally tested.
Android Not yet, incomplete graphics layer implementation is blocking it.
iPadOS Application and UI loads, but there is no puppet renderer and JDOM is incompatible.

Prerequisites

  • JDK 21 (LTS). The build is pinned to a 21 toolchain. Point JAVA_HOME at a JDK 21 — e.g. export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64. (Newer JDKs run Gradle fine, but are ahead of the Android toolchain.) Use a distribution JDK, not Homebrew's: :desktop:createDistributable runs Compose's checkRuntime, which hard-errors on a Homebrew JDK unless you pass -Pcompose.desktop.packaging.checkJdkVendor=false.
  • Android SDK with platforms;android-36 and build-tools;36.0.0. Set ANDROID_HOME (or create local.properties with sdk.dir=…). Only needed for the Android target.

The Gradle wrapper (./gradlew) pins the Gradle version so no system Gradle install required.

Common commands

./gradlew :desktop:run                                      #Launch the desktop editor
./gradlew :android:installDebug                             #Deploy to a connected Android tablet
./gradlew build                                             #Everything
./gradlew test                                              #Unit tests
./gradlew ktlintFormat                                      #Format all files according to .editorconfig
./gradlew -q :cli:run --args="dump model.moc3"              #Dump a CMO3/MOC3's contents to stdout
./gradlew -q :cli:run --args="convert model.cmo3 out.moc3"  #Convert between formats(Overwrites WITHOUT confirmation)
./gradlew -q :cli:run --args="diff a.cmo3 b.moc3"           #Compare two models semantically
# Cross-target the desktop build (default: host). -Pumamo.target swaps the bundled Skiko + LWJGL
# natives: linux-x64 | linux-arm64 | windows-x64 | macos-x64 | macos-arm64.
./gradlew :desktop:packageUberJarForCurrentOS -Pumamo.target=windows-x64
# Self-contained app image with a bundled JRE (what the release workflow ships).
# → app/desktop/build/compose/binaries/main/app/
./gradlew :desktop:createDistributable

-Pumamo.target is meaningless for createDistributable and must not be combined with it: an app image jlinks the host JDK into itself, so cross-resolving the natives would bundle one platform's Skiko/LWJGL inside another platform's runtime. Only the uber jar is portable that way. Pass -Pumamo.requireTargetIsHost=true (as CI does) to turn a mismatch into a build failure.

Running on WSL2 (WSLg)

Two things differ from a native Linux box (neither applies on a real desktop/GPU):

  • Use the system JDK 21, not Homebrew's. Homebrew's openjdk@21 has a few issues resolving libraries so it is easier to use the system installed JDK. Install sudo apt install openjdk-21-jdk and point JAVA_HOME at it: export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64.
  • Opt into the GPU. Mesa defaults to the llvmpipe software rasteriser on WSL; select the hardware D3D12 path explicitly. Compose's own Skiko renderer can't make a hardware GL context under WSLg, so let it fall back to software.
MESA_LOADER_DRIVER_OVERRIDE=d3d12 GALLIUM_DRIVER=d3d12 SKIKO_RENDER_API=SOFTWARE \
  ./gradlew :desktop:run

Cross-building for another platform

By default the desktop build bundles the natives for the machine running it. Pass -Pumamo.target=<os>-<arch> to bundle a different platform's natives instead which is useful for testing a Windows build from a WSL2/Linux checkout. Recognized targets: linux-x64, linux-arm64, windows-x64, macos-x64, macos-arm64.

# Produce a Windows-native runnable uber-jar from WSL2/Linux:
./gradlew :desktop:packageUberJarForCurrentOS -Pumamo.target=windows-x64
# → app/desktop/build/compose/jars/

This swaps both the Compose/Skiko renderer native and the LWJGL GL natives so the jar runs on the target. It is not a cross-compiler: the result is portable JVM bytecode plus the target's natives, so you still need a matching JVM on the target to launch it.

Don't combine -Pumamo.target with :desktop:run — that would load the target's natives in your host JVM and fail. The override is for producing artifacts and not running locally.

Module layout

Reusable library modules live under module/, runnable application targets under app/. Everything else at the repo root (gradle/, docs/, build files) is intentionally not a module. A module's Gradle path (:format) is kept flat and independent of its folder. See: settings.gradle.kts

Module Directory Targets Role
:format module/format jvm + android Cubism file family + art I/O (CMO3 read/write, …)
:reimport module/reimport jvm + android Source-art binding + non-destructive reconcile
:storage module/storage jvm + android App config/data dirs + file IO (okio) + native file dialogs (FileKit)
:settings module/settings jvm + android JSON settings: defaults←user merge, dotted get/set, change Flow → :storage
:runtime module/runtime jvm + android Puppet model + CMO3 ingest
:render module/render jvm + android Deformation eval (CPU) + renderer + morph-blend shaders (expect/actual: LWJGL / GLES) → :runtime
:ui module/ui jvm + android Compose Multiplatform editor shell
:desktop app/desktop jvm Desktop entrypoint (Compose Desktop + LWJGL viewport)
:android app/android android Android entrypoint (Activity + Compose + GLSurfaceView)

Shared logic lives in commonMain; platform code in jvmMain/androidMain via expect/actual.

Input, Commands, & Settings

  • Action registry. Every editor operation is a named Command in a central CommandRegistry (:ui, org.umamo.ui.action); menus, the command palette, and key bindings all dispatch through it, so handlers are never hardcoded in widgets. A command palette lists the registry with adaptive search.
  • Key bindings. Chords are stored logically, by key position plus a platform "primary" modifier (CMD on macOS, CTRL elsewhere), so shortcuts survive non-QWERTY layouts and map per OS. They resolve through a Keymap; a built-in default (defaultKeymap) along with editable user-persisted keymaps and presets(settings input.keybinding.preset).
  • Settings. A layered JSON tree: bundled defaults ← user overrides, addressed by dotted keys (:settings), persisted via :storage and emitting change events the UI reacts to.

File formats

Editor-format knowledge for CMO3, MOC3, and CLIP are reverse-engineered by black box observation. KRA is ported directly from Krita's own open-source GPLv3 code which is license-compatible with Umamo. All are written up under docs/format/.

File Format Support

Format Read Write Note
PSD 〇 - Photoshop (Read only)
CLIP 〇 - Clip Studio Paint (Read only)
KRA 〇 - Krita (Read only) - ZIP + maindoc.xml + tiled LZF rasters; ported from open source.
UMA 〇 〇 Umamo Model File
CMO3 〇 〇 Cubism Editor Model File - Compatible up to Cubism 5.4
MOC3 〇 〇 Cubism Distribution Model File - Compatible up to Cubism 5.4

Format Documents

Reverse engineered file formats have documentation in the docs/format/ folder.

Diagnostic CLI

The :cli module (app/cli) is a headless dump, convert, diff, atlas packing, and art meshing tool over the same CODEC and conversion stack the editor uses. Run it through Gradle; relative paths resolve against the repository root. Always pass -q so Gradle's own build output stays out of the tool's output. The tool writes data to stdout and diagnostics to stderr. The convert command will overwrite WITHOUT confirmation.

./gradlew -q :cli:run --args="dump model.moc3"               #Static-rig summary
./gradlew -q :cli:run --args="dump model.moc3 --sections"    #Container tier: per-section presence + counts
./gradlew -q :cli:run --args="dump model.cmo3"               #CAFF entry table + main.xml overview
./gradlew -q :cli:run --args="dump model.cmo3 --xml"         #Decompressed main.xml, byte-for-byte (Redirectable)
./gradlew -q :cli:run --args="dump model.cmo3 --puppet"      #Import to PuppetModel and summarize (Either format)
./gradlew -q :cli:run --args="dump art.psd"                  #Artwork canvas, folders, per-layer inventory + trimmed bounds
./gradlew -q :cli:run --args="extract model.cmo3 out/"       #Unpack the archive (Plaintext main.xml + layer PNGs) into out/model/
./gradlew -q :cli:run --args="atlas art.psd out/"            #Pack the layers into out/art/page_NN.png + placements.txt
./gradlew -q :cli:run --args="atlas art.clip out/ --preview" #Also recomposite the canvas from the packed pages.
./gradlew -q :cli:run --args="mesh art.psd out/ --preview"   #Auto-mesh every layer: out/art-mesh/mesh.txt + wireframe PNGs
./gradlew -q :cli:run --args="convert in.cmo3 out.cmo3"      #Resave (An unedited main.xml will reemit byte-identical.)
./gradlew -q :cli:run --args="convert in.moc3 out.moc3"      #Rebake (Fresh synthesis, NOT byte-identical by design.)
./gradlew -q :cli:run --args="convert in.cmo3 out.moc3"      #Full family: moc3 + model3.json + cdi3.json + textures
./gradlew -q :cli:run --args="convert in.moc3 out.cmo3"      #Fresh-graph synthesis (Always reports MissingSourceArt)
./gradlew -q :cli:run --args="diff a.cmo3 b.moc3"            #Semantic per-entity diff of two models

A moc3 input may also be given as its .model3.json manifest; textures and sidecars(cdi3/physics3/pose3/userdata3) are discovered through the manifest's file references.

dump, atlas, and mesh accept layered source artwork (.psd, .clip, .kra) or any flat raster, read as a one-layer document.

atlas

Packs a document's layers into atlas pages, writing page_NN.png and placements.txt to a new subdirectory named after the input. It reads every packed tile back out of its page and exits non-zero if any byte differs. Layers it cannot pack (no opaque pixels, or larger than a page) are reported rather than dropped silently.

Option Effect Default
--page-size=N Page side to pack against. 4096
--gutter=N Transparent spacing around every tile. 2
--extrude=N Edge pixels replicated into the gutter. 2
--rotate Allow quarter-turning tiles to pack tighter. Off
--visible-only Skip layers hidden by their own or a folder's eye. Off
--no-shrink Keep full --page-size pages instead of cropping them. Off
--preview Also write preview.png: the canvas recomposited from the packed pages (blend modes and layer opacity ignored). Off
mesh

Runs the art mesher over a document's raster layers, printing a report and writing it to mesh.txt in a new < A539 code><input>-mesh subdirectory. It exits non-zero if the mesher withheld a mesh after a failed structural check.

Option Effect Default
--layer=NAME Mesh only the layer with this exact name. Every raster layer
--preset=NAME standard, fine, or coarse: The settings the overrides below start from. standard
--visible-only Skip layers hidden by their own or a folder's eye. Off
--fill-holes Mesh over holes in the art (lace, a spider web) as one solid sheet instead of cutting them out. Off
--no-strand-rungs Mesh thin strands from their outline alone instead of as rung strips. Off
--preview Also write NNN-<layer>.png: each mesh over its art (outline magenta, interior edges blue, triangles under the minimum angle orange, vertices refinement added green). Off
--scale=N Magnify previews N times. 1

Each setting override replaces one value of the preset. Distances are in art pixels.

Override Sets Standard Fine Coarse
--alpha-threshold=N The least alpha (1-255) counted as art. 16 16 16
--outline-spacing=N The distance between outline vertices. 32 20 48
--interior-spacing=N The distance between inner-ring and lattice vertices. 48 28 72
--outer-margin=N How far outside the art the outline runs. 4 3 6
--inner-margin=N How far inside the art's edge the inner ring runs; 0 for none. 8 6 12
--minimum-margin=N The closest the outline may come to any art pixel. 2 1.5 3
--minimum-outline-points=N The fewest vertices one outline ring may have. 6 8 4
--vertex-budget=N The most vertices one mesh may have. 1024 1024 1024
--minimum-angle=N The angle, in degrees, refinement brings every triangle up to; 0 turns refinement off. 20 24 15
--interior-thinning-limit=N Over the vertex budget, how many outline spacings the interior may thin to before the outline thins with it. 4 4 4
--strand-width=N The art width below which a stretch of art is a strand, meshed as rungs. 40 26 60

The report has one row per layer, then the run's smallest triangle angles in 5-degree buckets.

Column Meaning
order, name, raster The layer's order, name, and raster size.
vertices, triangles The mesh's vertex and triangle counts.
outline Outline rings / outline vertices.
refined Outline chords split because they came too close to the art or cut it off.
inner Inner rings / inner-ring vertices.
lattice Interior lattice vertices.
strands Strands / rungs / centerline vertices.
steiner Vertices refinement added toward the minimum angle.
minAngle The smallest triangle angle, in degrees.
under5, under10, under20 Triangles whose smallest angle is under 5, 10, and 20 degrees.
unfixable Triangles left under the minimum angle that refinement could not help: an angle the outline itself makes, or a spot too tight to split.
milliseconds, notices The time taken and the mesher's notices.

Running Tests

All tests can be run with ./gradlew test or individual tests can be run like so:

./gradlew :interop:jvmTest --tests "org.umamo.interop.PuppetModelDiffTest"

Corpus Testing

Each CODEC and reader have tests that run against real samples that you can supply. Note: The /test/corpus is intentionally gitignored to prevent accidentally committing private data. If you don't supply samples then the tests will automatically skip.

Put your samples at test/corpus/ and they are picked up automatically:

test/corpus/cmo3/    EricaTamamo.cmo3  (the model the CMO3 gate's exact counts are pinned to)
test/corpus/moc3/    Put each model's files in a separate subdirectory.

Artwork:
test/corpus/clip/    test/corpus/psd/  test/corpus/krita/   test/corpus/tiff/  test/corpus/jpeg/
./gradlew :format:jvmTest                                                                                                                        #Corpus automatic discovery.
./gradlew :format:jvmTest -Dcmo3.sample=/path/to/Model.cmo3                                                                                      #Point at one explicitly.
./gradlew :format:jvmTest --tests "org.umamo.format.cmo3.tools.ModelGenerator" -Dcmo3.generate=true -Dcmo3.gensample=/path/to/Model.cmo3 --rerun #Generate new CMO3 model and registration.  Make sure to run ktlintFormat afterwards to clean up.
./gradlew :ui:jvmTest --tests "*.EditGrabPerfProbeTest" -i                                                                                       #Edit-mode perf probe over moc3.perfSample (test/corpus/moc3/modelF by default).  Print-only: -i (--info) shows the rows, or read build/test-results.
./gradlew :render:jvmTest --tests "*.EditGrabRenderPerfProbeTest" -i                                                                             #Its render-thread twin (needs a GL context).

Legal & Trademark Notice

Umamo is an independent, community-developed project. It is not affiliated with, authorized by, endorsed by, or sponsored by Live2D Inc. (formerly Cybernoids Co., Ltd.) or any of its affiliates.

"Live2D®" and "Cubism" are trademarks of Live2D Inc. in Japan and/or other countries; all other trademarks are the property of their respective owners. These marks are used here only nominatively, to describe file-format compatibility, and no endorsement, affiliation, or sponsorship is implied.

Contributors

WANTED: Human translations for various languages.(Japanese, Chinese, Korean, Spanish, French, German, etc.) The English strings are located at: module/ui/src/commonMain/composeResources/values/strings.xml

At the moment I'm not accepting large code contributions from outside contributers. Small fixes are accepted, but please keep in mind that at moment the development speed on this project is rapid. I'm might make your change obsolete by the time I get around to reviewing it.

(Once large changes are accepted in the future.) If you are planning a large change that touches many files then break it down into a stack of smaller pull requests that build on each other. For example, if you're adding a new export format:

  • PR 1: Add the underlying data structures/parser with tests, no UI wiring yet.
  • PR 2: Add the export logic that consumes those structures, merged on top of PR 1.
  • PR 3: Wire up the UI/CLI flag that exposes the feature, merged on top of PR 2.

Each PR should be reviewable and mergeable on its own instead of being submitted as one giant diff. This makes review faster and makes it easier to bisect regressions.

Provenance & Reverse Engineering

Umamo's editor-format layer (.cmo3/.moc3 read/write, .clip ingest) is a clean-room reimplementation built from black-box observation of file outputs and independently produced documentation.

By contributing you affirm:

  1. No use of official Live2D/Cubism source or decompiled binaries as a basis, knowledge only from observing file outputs and public, independently authored documentation.
  2. You are not bound by a Live2D agreement your contribution would breach, and will disclose any such license before contributing.
  3. Are not a past or present employee of Live2D or Cybernoids.

If you have been exposed to Live2D source code or decompiled binaries, please do not contribute.

AI Usage Disclaimer

Large Language Models(LLM) are used to assist with rubber ducking and housekeeping tasks. Assisted tasks include planning development road maps, function documentation, and helping to keep the developer focused. AI has not been and will never be used to decompile or otherwise discover the source code of protected software.

License

GPLv3 See LICENSE

About

Umamo is an open-source cross-platform rigging editor for 2D puppet animation, with first class pen and touch support, built as a drop-in replacement for the Live2D Cubism Editor.

Topics

Resources

Stars

191 stars

Watchers

6 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

0