Make a Spriter creature¶
This guide takes a creature from a Spriter project to a local mod. You need the
installed Windows game, its ExampleMod/ folder, Mod Prep, a text editor, and
Spriter for creating or editing animations. You do not need the game's source
code, Visual Studio, or a content compiler.
Spriter Pro is separate software. This guide uses its built-in atlas export, which BrashMonkey documents as a Pro feature. You can complete the first test with the already exported Jacked Kangit before buying or opening Spriter. Demina and its XNA prerequisite are for a different animation format; they are not needed for this workflow.
1. Get a working creature into your own pack¶
Start with Make your first mod and create a Mod Prep
project with UniqueModName set to my_creatures. Use a separate editable
project folder and Install / Refresh Test Copy when testing.
From ExampleMod/ beside the game executable, copy these into that project:
creature_jackedkangit.json- The complete
Creatures/JackedKangit/directory, including its Lua script andAnimations/files
Rename the copied JSON file to creature_my_kangit.json. Inside its Creature
object, change UniqueIdentifier to my_kangit and Name to My Kangit.
Keep the other fields unchanged for this first test. The new full creature ID
is my_creatures.my_kangit. The asset folder and Lua table can keep their
original names; they are not the creature's saved identity.
Use your own permanent IDs for a released pack. Changing the mod name or
creature identifier later makes a different creature to saved games. Give
creatures distinct Name values too; registration data is also looked up by
name. Keep the original Example Mod disabled during this first test.
Press Validate, install the test copy, enable it in Mods, and restart the game. In a disposable single-player world, open chat and enter:
/creative
/spawn my_creatures.my_kangit
The creature spawns near your character and uses the sample's behavior. The included script is hostile, so allow room to observe it. A successful spawn checks your pack identity, copied files and paths before you change its art. The starter item created by Mod Prep can remain during this test.
2. Prepare your animation project¶
Keep your editable Spriter project and original image pieces outside the export folder. The shipped Jacked Kangit is an already packed example:
Creatures/JackedKangit/
jackedkangit.lua
Animations/
jacked_kangit.scml
atlas.json
image.png
Its SCML and atlas are useful references for names, pivots and the output layout. Keep your own unpacked art/project as your editable master when making a new rig.
Use a single entity in the exported SCML. The game selects the first entity; there is no creature JSON field for choosing another entity in that file. Author the unflipped rig facing left; the game mirrors it for right-facing movement. Keep the feet close to the project's ground origin so body alignment is easy to adjust.
The copied Lua script and the game's movement actions expect these clip names:
| Clip | Loop? | Purpose |
|---|---|---|
idle |
Yes | Standing and the default pose |
walk |
Yes | Walking actions |
run |
Yes | Running actions |
bite, swipe |
No | The sample's two attacks |
flinch |
No | The sample's damage reaction |
death |
No | The sample's death animation |
Keep this spelling and casing when following the example. A different script
can request other clips, but changing names requires updating every request.
Give one-shots a useful duration and turn off looping in Spriter; a looping
attack will not send the completion callback used to release the script's
attack lock. The shipped flinch is a very short pose, not a full reaction
animation.
Use clear, unique names for the visible sprite timelines you intend to use as
hit locations. The example names include jacked_kangit_head and
jacked_kangit_mandible. A skeletal bone label and the attached sprite
timeline's name can differ; the collision fields below should use the actual
sprite timeline names. Keep the rig hierarchy consistent between clips so
the game can blend their poses.
3. Export SCML with a texture atlas¶
Use the atlas workflow described in BrashMonkey's export instructions:
- Save the editable project. Choose File → Generate spritesheets for project images.
- Select a separate export folder, outside the editable project's image directory.
- Enable save spritesheeted project, so the export includes an SCML clone that refers to the atlas. A PNG alone is insufficient.
- Start with Never generate multiple spritesheets. Choose an atlas size large enough to fit the art; 1024 is the documented default, not a required game size. Increase it if the export cannot fit.
- Export, then copy the resulting SCML, atlas JSON and PNG together into your
mod's creature animation directory. Point
AnimationPathat this exported SCML clone.
Use SCML (XML), rather than SCON or a baked frame-strip export. The runtime plays the rig and its timelines. It reads ordinary PNG and JSON files directly; there is no XNB conversion or game rebuild step for these mod assets.
Keep the exported filenames and relative layout consistent:
| Reference | Must resolve to |
|---|---|
Creature JSON AnimationPath |
The SCML file, relative to the mod root |
SCML atlas entry (<atlas><i name="atlas.json"/></atlas> in the example) |
The atlas JSON, relative to the SCML directory |
SCML folder atlas="0" |
The matching atlas entry's ID |
Atlas JSON meta.image |
The PNG, relative to the SCML directory |
Each SCML image file name |
An exact key in that atlas's frames object |
The names atlas.json and image.png are the example's choices, not mandatory
filenames. Keeping all three output files together is the simplest layout.
Use relative paths and matching case throughout; do not leave drive-letter
paths to your art folder.
The atlas must use a JSON object/hash for frames, keyed by image names.
An exporter option that writes frames as an array is a different format.
Retain the export's frame rectangles, original sizes, trim offsets and rotation
flags. The game uses that metadata to place trimmed/rotated pieces correctly;
resizing or rearranging the packed PNG alone breaks it. Export at the original
image scale (1×); the atlas's meta.scale does not rescale the rig at runtime.
The loader can read multiple atlas entries, but each SCML folder must select the correct atlas and all its named images must exist there. Start with one atlas before attempting a larger layout. Use an atlas for creature releases: loose-image loading does not provide the same sprite-based hit detection. Keep soundlines out of this first export. Spriter's embedded sounds are not the mod's ordinary loose-audio workflow; add audio through the documented World API instead.
4. Connect the art and behavior¶
In your copied creature_my_kangit.json, keep the Creature root and update
the fields for your exported rig:
| Field | What to set |
|---|---|
AnimationPath |
Pack-relative path to the exported SCML, including .scml |
DefaultAnimation |
idle for this example |
LuaScriptPath |
Pack-relative path to the creature's Lua script |
BodyWidth / BodyHeight |
Physics box width/height in game pixels |
AnimationOffsetX / AnimationOffsetY |
Move the drawing relative to that box |
ConfigJumpHeight, WalkSpeed, RunSpeed, ConfigViewRange |
Movement and target-search settings used by the creature |
CritBoneNames |
Sprite timeline names that receive critical hits |
MeleeBones |
Named melee contact locations and optional offsets |
RegistrationData |
Health, melee damage, description and codex category |
DropData |
Optional item drops; use full registered item IDs |
The rig is drawn at the bottom center of the physics box, plus the animation offsets. The animation's visible outline does not resize that box. Check feet, walls and steps in-game; adjust the box for movement and the offsets for art alignment. The sample's numeric values fit Jacked Kangit and are not universal defaults for a new creature.
Keep the sample Lua script for the first art replacement. It already imports
Content/Lua/Creature, creates the creatureTable expected by the loader,
and implements movement, targeting, attacks, damage and death. When adapting
it, preserve that setup and use the allowlisted
Creature API. AnimationPath supplies art; it does not
generate AI behavior.
The sample calls self.creature:PerformAction("IDLE"),
"WALK_LEFT" / "WALK_RIGHT", and "RUN_LEFT" / "RUN_RIGHT" for
locomotion. It starts an attack with, for example,
self.creature:TransitionToAnimation("bite", 0.1); the 0.1 is a transition
in seconds. Update the script's clip names and fallback lock durations when
your exported attack lengths change. Its World:getTimeDeltaMS() timers use
milliseconds.
Melee contact and attack timing¶
For the sample rig, a melee location looks like this inside MeleeBones:
{ "BoneName": "jacked_kangit_head", "OffsetX": -28.5, "OffsetY": 15.2600002 }
Use a sprite timeline that is present during the strike. The offset moves the contact point in game axes from that sprite's animated position; X mirrors with facing, but the offset does not rotate with the limb. Use zero offsets first and tune them in both facings.
Requesting bite, swipe or attack opens melee collision immediately,
including during the transition into the clip. This is the sample's default
contact model. Spriter event keys can close and reopen the window as the
clip advances:
| Where in the clip | Event name |
|---|---|
| At the beginning of playback | disableCollisions |
| At the first damaging pose | enableCollisions |
| After the last damaging pose | disableCollisions |
Use event timelines named enableCollisions and disableCollisions, with
keys at those points; these are not sound labels or ordinary bone names.
The script can also receive them through keyframeTriggerEvent. A time-zero
disable event is processed when playback advances, so it does not guarantee a
harmless initial blend. Test contact during the transition as well as the
visible strike.
For a fully event-controlled windup, a custom clip name does not automatically open collisions. Adapting the sample for that requires stopping locomotion before the transition, authoring the enable/disable events, and updating the script's attack lock and completion-name checks. Custom names also lack the standard attacks' automatic foot-planting behavior. Keep the standard sample attacks for the first working creature, then change this behavior deliberately.
Do not issue idle/walk/run actions during the attack: those actions clear the
collision window. The copied script holds an attack lock, releases it from
animationCompleted(animationName), and lets the next update choose
movement. Keep this pattern. Do not start another transition from inside
animationCompleted; set a flag or clear a lock and transition in update.
That callback is for non-looping Spriter clips. Demina's animationComplete
keyframe marker is not required to finish a Spriter clip.
5. Test the exported copy¶
After every export or JSON/Lua edit:
- Validate in Mod Prep, then Install / Refresh Test Copy.
- Restart Signs of Life. Load Now does not reload an already Loaded pack; a restart also clears the cached animation and atlas files.
- Open a disposable single-player test world and spawn
my_creatures.my_kangitagain. - Observe idle, walking and running in both directions. Check feet, facing, pivots, drawing order, trimming and the body's fit against terrain.
- Let it attack from both sides. Check the windup, damaging pose, recovery and return to movement. Check that flinch/death stop looping and that damage/drop values match your JSON.
- Save and reopen the test world with the same pack enabled. Before distributing a multiplayer creature, test matching pack versions on host and client too; the host runs its spawning and behavior.
Validation catches pack errors; it does not prove the rig's alignment, all timeline names, combat timing or Lua behavior. Keep a known-working exported copy so you can compare one change at a time.
Registering the creature does not make it spawn naturally. Once manual spawning works, add an ambient spawn rule or a spawn entry in a custom world, using your full creature ID.
Troubleshooting¶
| Symptom | Check |
|---|---|
Unknown creature when spawning |
Pack enabled/Loaded, creature_ filename prefix, Creature root, exact mod.id and a restart after edits |
| Missing image or atlas lookup failure | Exported SCML clone, SCML atlas references, meta.image, relative paths/case and object-style frames keys |
| Pieces shifted, cropped or rotated incorrectly | PNG and atlas JSON from the same export, including trim/rotation metadata |
| Creature floats, clips into ground or catches on walls | Physics box separately from drawing offsets and rig origin |
| Animation does not change | Clip spelling, requested clip actually exported, script installed and current pack reloaded |
| Attack repeats or never releases its lock | Non-looping clip, animationCompleted handler, and a fallback lock longer than the new clip |
| Attack looks right but causes no damage | Named sprite exists in the strike pose, melee points reach the target, collision events are ordered, and locomotion is not canceling the window |
| Old artwork persists | Refresh the installed test copy and fully restart the game |
Distribute the playable files¶
Keep modinfo.json, the creature_*.json definition, Lua script, exported SCML,
every referenced atlas JSON and its PNGs inside your pack. Keep the editable
master project and original art backed up separately. Other players need the
exported files, not a Spriter installation.
Use Mod Prep to validate and stage the complete pack, then follow the publishing steps. Local folder/ZIP sharing can be tested without Workshop; Workshop submission requires Steam and an internet connection.