Skip to content

Author with Gymnast Tool Suite

Gymnast Tool Suite provides the Blender authoring scene, IK controls, model tools and native animation exporter. Eclipse supplies validation and packaging into a regular Lua mod with a map battle. Start here for visual character authoring.

The tested combination is Gymnast 1.1.5, repository revision b44dea8ae549ff52ec8d08d7d1ad86f53db80702, and Blender 5.0.1. The upstream add-on advertises Blender 4.4+, but its current SF2 scenes use file format 405.91: Blender 4.4.3 and 4.5.3 warn about possible data loss. Use Blender 5.0+ with the bridge. Your Blender 3.6 installation can remain installed separately.

Eclipse does not bundle or modify Gymnast. The bridge loads the checkout you supply and registers its add-on for that Blender session. The upstream repository includes its GPL license; retain attribution and check asset permissions when distributing authoring files or exported content.

Run from the Eclipse repository root. Obtain Blender from its official downloads. A portable build works.

Terminal window
git clone https://github.com/FlipThoseTitle/Gymnast-Tool-Suite.git Temp/Gymnast-Tool-Suite
git -C Temp/Gymnast-Tool-Suite checkout b44dea8ae549ff52ec8d08d7d1ad86f53db80702
dotnet run --project Tools/AssetPacker -- extract Assets/StreamingAssets/SF2Content/ArtBundles/MODELS.tar.lz4 Temp/CharacterCore
$blender = 'C:\Program Files\Blender Foundation\Blender 5.0\blender.exe'
.\Tools\Animation\OpenGymnast.ps1 -Blender $blender -Suite Temp/Gymnast-Tool-Suite -Rig Temp/CharacterCore/models/mdl_skeleton.xml -Blend Temp/MyGymnast/character.blend

Set $blender to your actual executable. If the checkout or extracted assets already exist, reuse them. The open command creates the authoring file only when it is missing; subsequent runs open your existing work. It does not overwrite the earlier Temp/MyCharacter/character.blend point-rig experiment or change Blender preferences.

The prepared copy has the upstream visible capsule body and IK armature, framed in an orthographic viewport. The armature is selected in Pose Mode. Point labels are hidden and the underlying node objects are protected from accidental selection. They remain present for export. The animation panel is configured for the SF2 IK armature and canonical skeleton. Press N for Gymnast’s sidebar if needed.

Use the armature’s HandIK_1, HandIK_2, HeelIK_1, HeelIK_2 and body controls. Insert location/rotation keyframes on the controls; the native point objects follow through the upstream rig constraints. Start with a visible arm motion and check both the body and its controls while scrubbing.

The prepared range is frames 1–60 at 60 fps. Every frame exports as one native sample with mid_frames = 0. For existing 20 fps sample data, use --mid-frames 2 and a 20 fps scene; the bridge verifies the relationship instead of silently retiming. Native end frame is sample_count - 1: frame bounds index stored samples. Interpolation changes playback timing, with nominal sample spacing (mid_frames + 1) / 60 seconds.

Keep Gymnast’s scene scale. Its native coordinate conversion is (Blender X, Blender Z, -Blender Y) without a ×100 multiplier. The earlier low-level importer used different Blender units; do not mix its point objects into a Gymnast scene. Keep every required object name and use the same dependency rig when importing and exporting animations.

The upstream animation guide explains animation import, mirroring, interpolation and weapon-node options.

Use Gymnast’s Model Tool to import native XML geometry or export modeled geometry. Choose the appropriate model type and dependency rig. Its head/body/foot gear and weapon workflows handle the corresponding native attachments. Save optional geometric overlays as XML files before packaging.

Pass character overlays with --skin. They are appended to the body/equipment composition. Equipment replacements should use the matching typed equipment API; a skin overlay does not automatically replace the character’s weapon or armor. Preserve original rig names/order when reusing native moves and equipment. Native rigs, attachment math and collision behavior still constrain custom models.

Save your .blend, then run:

Terminal window
& $blender --background --factory-startup Temp/MyGymnast/character.blend --python-exit-code 1 --python Tools/Animation/GymnastBridge.py -- export --suite Temp/Gymnast-Tool-Suite --rig Temp/CharacterCore/models/mdl_skeleton.xml --output Temp/MyGymnast/move.bin --package Temp/MyGymnast/local.character-preview --mod-id local.character-preview

Add --skin Temp/MyGymnast/skin.xml for an exported overlay; repeat for up to 16 files. Use fresh output paths for subsequent exports. Existing files/packages are refused to protect edits. The package folder’s name must match --mod-id.

The bridge checks missing node objects before invoking Gymnast’s exporter, verifies finite evaluated coordinates and compares every exported point against the evaluated Blender pose. It then validates the body, optional skins, node counts and binary payload. The upstream exporter can otherwise write zero coordinates for missing nodes. The standalone packager also rejects required bindings collapsed to zero for the entire clip, but cannot prove the names of an arbitrary binary’s points because native binaries do not contain them.

If you already exported through Gymnast’s UI, package that .bin directly:

Terminal window
python Tools/Animation/PackageCharacter.py --rig Temp/CharacterCore/models/mdl_skeleton.xml --animation Temp/MyGymnast/move.bin --output Temp/MyGymnast/local.character-preview --mod-id local.character-preview

This path validates file structure; only the Blender bridge can compare the output with its source pose. Neither path rescales, reorders or rewrites the animation bytes. Eclipse stores the same payload as assets/animations/authored.bytes.

Add --playable to the bridge’s export --package command, or to the standalone packager. The generated fight then uses your owned warrior as its player and as its AI opponent. Without the flag, the player keeps the normal campaign character and only the opponent uses the export. The option defaults to false; it does not change the model or animation bytes, rig order, timing, or campaign profile.

Terminal window
python Tools/Animation/PackageCharacter.py --rig Temp/CharacterCore/models/mdl_skeleton.xml --animation Temp/MyGymnast/punch.bin --skin Temp/MyGymnast/skin.xml --output Temp/MyGymnast/local.playable-character --mod-id local.playable-character --playable

Enable the complete generated mod and enter its map preview. Punch plays your primary clip; additional clips use their declared controls. The opponent uses its generated Lua tactic to choose eligible authored clips. The generated move conditions, events and intervals use the current declarative Lua format. Moves use direction = "face_enemy" to face the opponent when playback starts. For example, { character = character } restricts your Punch override to this warrior. The encounter’s player_character selects the owned warrior; no combat form-swap or persistent profile replacement is needed. Use a fresh package path to preserve earlier authored work.

--playable on the Blender bridge requires export and --package; using it for prepare/open or an unpackaged binary is an error. It combines with standalone --clip packaging, including each clip’s control and timing. It changes only the generated encounter role and player instructions. The primary and additional preview moves have no attack intervals; inherited native attacks can still deal damage. To build a combat moveset, add the typed attacks and hit timing in Lua.

Export each motion separately with the same dependency rig, then add named clips to the standalone packager. Each --clip takes name, control, mid-frames, file:

Terminal window
python Tools/Animation/PackageCharacter.py --rig Temp/CharacterCore/models/mdl_skeleton.xml --animation Temp/MyGymnast/punch.bin --clip kick Kick 0 Temp/MyGymnast/kick.bin --clip flourish Magic 2 Temp/MyGymnast/flourish.bin --output Temp/MyGymnast/local.moveset --mod-id local.moveset

The primary --animation keeps the authored_move name and Punch input. Additional names require 1–48 lowercase letters/digits/underscores, starting with a letter; authored and authored_move are reserved. Controls must be distinct: Kick, Ranged, Magic, Up, Down, Forward, or Back. Forward/Back are relative to facing. This allows eight preview clips including the primary one. Directional bindings may replace ordinary movement for the authored warrior; choose combat buttons first when testing. Edit the generated Lua for advanced input combinations or a larger moveset rather than relying on this preview binding scheme.

Each clip’s mid-frames is an integer from 0 to 8 and must match its source sampling. It changes interpolation spacing, not binary sample count or native end-frame indices. Clip bytes stay unchanged. Every clip is checked against the shared rig before publishing the package; an invalid clip prevents the output directory from being created. The package permits at most two million node samples in total. All existing output protection and skin validation still apply.

Each additional clip receives assets/animations/<name>.bytes, its own <name>.rig.json timing/hash/control sidecar, and preview-<name>.html. The original preview stays at preview.html. scripts/character.lua returns warrior, the original move, and a moves table keyed by authored_move and your additional names. The preview AI cycles through eligible clips, skipping unavailable ones and waiting between requests. All generated moves still deal no damage until you author attack intervals.

The package contains a manifest, native assets, localization, scripts/character.lua, scripts/main.lua, a rig fingerprint sidecar, and a point-motion preview.html. The preview respects sample spacing. Body and skin appearance should be inspected in Blender and the game, not inferred from the point preview.

Copy the complete local.character-preview folder into Eclipse’s Mods directory, preserving any existing work under that ID. Enable it through Mods → Apply & Restart and find Character Preview using the bottom map-page dots.

The repeatable fight uses your authored warrior as the opponent, and also as the player when packaged with --playable. Its Lua AI selects eligible authored clips with a pause between requests. This allows you to watch the export without creating another fight script. Authored preview moves have no attack intervals; inherited native moves can still deal damage. Entry costs and rewards are empty.

Edit scripts/character.lua to add the typed attack intervals, change input conditions or supply your own tactic. scripts/main.lua is ordinary mod code and can be replaced by your own battles. Inspect both facing directions, rig/skin deformation, equipment attachment, movement, hit reactions and contact timing. A successful binary read does not establish all of those behaviors.

Tools/Animation/TestGymnastPipeline.ps1 -Blender <executable> -Suite <checkout> exercises the supplied IK/body scene, an authored hand motion, upstream model and animation exports, source-pose comparison, packaging, real Lua map/mode/AI bindings, the watched and playable package roles, and the unchanged Unity animation reader. It writes an inspection render and test artifacts under Temp.

Tools/Tests/Modding/TestModAiEligibility.ps1 executes the recovered AI shortlist and priority methods with controlled model/animation services. It checks that character restrictions, uninterruptible state and higher-priority input moves filter the candidate list; event-only animations are excluded. Generated package tests also exercise Lua clip cycling, pacing and unavailable-clip fallback. Neither test simulates contact physics or proves that authored geometry looks correct in a fight.

The low-level point-rig tools remain available for format work. They also include explicit armature retargeting using a creator-supplied bone mapping and calibration frame. They are not the recommended visual authoring interface. Automatic skeleton matching, arbitrary Blender shaders, complete custom character controllers/forms and full-game visual/combat acceptance remain separate requirements.

The full-game Tools/Tests/CharacterForms/TestPackagedCharacterUnity.ps1 runner accepts a generated Gymnast integration package. It uses a marked isolated project and fresh profile to check native models/weighted skin helpers, player selection, native Punch dispatch, both facing directions, exported point motion, opponent Lua AI and cleanup. Its controlled test uses the canonical 67-point rig and the integration scene/skin; it is not arbitrary mesh/rig, attack-contact, physical-device, mobile, or exported-platform acceptance. Existing format and reader checks remain narrower than a game playtest.

Both generated roles have full-game acceptance in Unity 6.6: 28 checks for the playable package and 16 for the default opponent-only package. The exported test skin is a small original triangle bound to head landmarks. Native macro-node weights update XY only; these checks do not prove animated skin depth or a complete original outfit. Exported preview clips still need authored attack intervals before they become damaging combat moves.