Animations and Animation Bases
Create animation bases (a skeleton plus its clips), import, trim, retime and preview clips, assign them to NPCs, and read the animations.json format.
10 min read
What an animation base is#
Characters in Vastopia do not carry their animations inside their model files. Instead, every NPC (and the player) points at an animation base: a named skeleton plus a library of animation clips made for that skeleton. The base is the thing you animate; the NPC model is just the skin that gets grafted onto it in game.
This split is what lets you share one set of clips across many characters. A dozen humanoid NPCs with different meshes can all use the same humanoid base and play the same idle, walk, run and attack clips. Import a new clip once and every NPC on that base can pick it.
A base has:
- a Base ID - a string such as
humanoidorkaykit_skeletonthat NPCs reference, - a Display Name,
- a Skeleton scene (
assets/skeletons/<base_id>_skeleton.tscn) holding only the bone hierarchy, no meshes, - optionally a default model to preview and fall back on,
- a list of clips, each with a numeric id that is only meaningful inside that base. Clip files live at
assets/anims/<base_id>/anim_<id>.tres.
Every new project ships with one base, humanoid: the player rig (a Rigify DEF-* skeleton with 33 bones) and three clips - 1 idle (2.0 s), 2 walk (1.375 s) and 3 run (0.92 s). The player character in the client is built from this base's skeleton and always plays clips 1, 2 and 3 as idle, walk and run, so the base is protected: it shows a default badge in the editor and cannot be deleted, and you should not renumber those three clips.
When to create a new base#
Create a base when you bring in a character whose skeleton differs from the ones you already have - a quadruped, a dragon, a different humanoid rig from an asset pack. If an asset pack ships several characters on the same rig (a common "one skeleton, many skins" setup), create one base from any of them and point every NPC in the pack at it.
You rarely open the Animations tab to create a base by hand, because the NPC create flow does it for you: dropping an animated model on the NPC create page offers Create new animation base from this model or Use existing animation base. The Animations tab is where you come back to add clips, clean them up and check what uses them. See NPCs for the NPC side.
Create a base from a model#
- In the Data Editor, open the Animations tab and click + New Anim Base, or click the Animations card on the Create New page. The card accepts an animated mesh (
.glb,.gltf,.fbx) - drop one, drag one from the model shelf, or click click to browse. - Type a Name. Animation bases have no ID dropdown; the id is derived from the name (lowercased, spaces replaced by
_). You can also pick a saved template under Start from a template. - Press Finalize Animation. The base opens in its own tab. The dropped file is consumed whole: its skeleton is extracted to
assets/skeletons/<base_id>_skeleton.tscnand every animation clip it contains (except the engine'sRESETtrack) is written toassets/anims/<base_id>/and listed under Animations. - Press Save Animation Base (or
Ctrl+S) to write the base toassets/data/animations.json.
.fbx files are converted through Blender first. If Blender is not installed the import fails with an error in the console; use .glb/.gltf or install Blender.
Set the skeleton by hand#
An empty base (one created without a file) needs a skeleton before clips can be previewed. In the Animation Base card:
- Extract… - pick a
.glb,.gltfor.fbx; the firstSkeleton3Din it is copied, meshes stripped, toassets/skeletons/<base_id>_skeleton.tscn. - Load… - pick an existing skeleton
.tscn; it is copied into the project under the same conventional name.
Both buttons need a Base ID first. The id becomes read-only once the base has been saved.
The animation base editor#
An open base has a 3D Preview on the left and three cards on the right: Animation Base, Animations and Selected Animation.
Preview#
- Model: picks any model from the asset library to animate. Clearing it falls back to the bare skeleton (Skeleton only), with the bone overlay switched on so there is something to see. When a base is opened it loads the best subject it can: the base's stored model, then the built-in player mesh for the
humanoidbase, then the first NPC that uses the base, then the skeleton. - Set as Base stores the previewed model on the base as its default model and saves immediately. NPCs that use this base and have no model of their own fall back to it, and the base reopens with it. The built-in player mesh cannot be stored (it is not part of your project), and neither can a model that lives outside the project unless the asset library owns it - the path must be project-relative or every NPC adopting it would break in game.
- Viewport: left-drag orbits, right-drag looks around, middle-drag pans, wheel zooms.
- Transport: Play / Pause, the stop button, a preview-only Loop toggle, a Speed slider (0.1x-3.0x) and a Time scrubber. Neither Loop nor Speed here changes the clip; the clip's own loop mode is under Selected Animation.
- Meshes and Bones toggle the model geometry and the bone overlay.
Used by NPCs#
Below the preview, Used by NPCs lists every NPC whose animation base is this one, with the number of clips it references. Click an NPC to load its model into the preview and check a clip on the rig that really plays it; double-click or press Open NPC to jump to it in the NPC editor. Only NPCs that use the selected clip narrows the list, and the refresh button re-reads npcs.json.
Animations#
The clip list has three columns: Animation (id · name), Length and NPCs (how many NPCs reference the clip). A star and idle/walk/run after the name mark the base's default clips. Filter clips… searches names and tags. Click a clip to play it on the preview model; double-click restarts it.
Add ▾ offers three sources:
| Menu item | What it does |
|---|---|
| Import from model (.glb / .gltf / .fbx)… | Extracts every clip in the file. |
| Add animation resource (.tres)… | Adds one Godot Animation resource (.tres / .res). |
| Add FBX animation (.fbx)… | Imports clips from a single FBX through Blender. |
Each new clip gets the id after the highest one already in the base (gaps are never refilled) and is saved as assets/anims/<base_id>/anim_<id>.tres. Root-level transform tracks on nodes named Armature, Root, Character or RootNode are stripped on import - these are FBX artifacts (100x scale, -90 degree rotation) that fight a normalized skeleton.
Remove takes the selected clip out of the base. The .tres file stays on disk.
Right-click a clip for Set as Default Idle, Set as Default Walk, Set as Default Run (and Clear Default once set). When an NPC picks this base, its Idle Anim / Walk Anim / Run Anim dropdowns are pre-filled with these defaults.
Selected Animation#
| Field | Notes |
|---|---|
| ID | The number NPC definitions and the server reference (up to 9999). |
| Name | Display name. |
| Duration + Retime | Type a new duration and press Retime to rescale every keyframe - longer plays slower, shorter plays faster. The preview speed slider does not do this. |
| Loop | None - play once, Linear - restart at the end, Ping-pong - play back and forth. Stored in the animation resource; this is what the game uses. |
| In-Place | Strip root motion (movement driven by the game). When on, the root bone's horizontal travel is removed so the server's movement drives the character instead of the clip walking away from its spawn. |
| Trim | Drag the in/out handles on the timeline bar to the part worth keeping and press Crop; the clip is rebased to start at zero and keys are sampled at both ends so the poses hold. Reset restores the original clip. |
| Duplicate | Copies the clip to a new id and .tres file (<name>_copy) - make a retimed or in-place variant without touching the original. |
| Re-import FBX… | Replaces the clip's data from an .fbx via Blender while keeping its id, name, tags and in-place flag. |
Trim, retime and loop-mode edits are derived from a pristine copy each time, so you can keep adjusting and Reset always gets the original back. The preview plays the pending edit, but nothing touches the .tres file until you press Save Animation Base.
A line under the fields reports which NPCs use the clip and in what roles, for example Used by: Guard (Idle), Knight (Attack).
Assign clips to NPCs#
In the NPC editor's Animation section you pick the Anim Base and then an Idle Anim, Walk Anim and Run Anim from that base's clips. The Server Animations section maps named server animations - the predefined Attack, Block and Death, plus Custom... names - to clip ids; the server's combat code looks up Attack, Death and Block by those exact names when it plays hits and deaths. Everything an NPC chooses is saved by its numeric clip id together with the base id, which is why a clip's id must stay stable once NPCs reference it.
Delete a base#
Right-click a base in the Animations list (Shift/Ctrl to select several) for Delete Animation Base, or press Delete / Backspace. After confirmation the base entry is removed along with the files it owns: each clip's .tres, the skeleton scene, and the anims/<base_id>/ and models/<base_id>/ folders. The humanoid base is always kept. NPC definitions are not rewritten when a base is deleted, so reassign any NPC that used it.
How the game uses a base#
- The client reads
assets/data/animations.json, finds the NPC's base, builds the skeleton fromskeleton_path, grafts the NPC's mesh onto it, and loads the idle/walk/run clips by id (assets/anims/<base_id>/anim_<id>.tres), honoringin_place. - The player character is built the same way from the
humanoidbase with clips 1, 2 and 3. - Server-triggered animations (combat, scripts, the
::anim <id>command) send a clip id; the client loadsanim_<id>.tresfrom the entity's base folder.
Custom rigs and skin binding#
Because the client plays clips on the base skeleton, not on the mesh's own skeleton, the mesh's skin has to be rebound to the base by bone name. The editor names every skin bind when it packs a model into .scn, and the client maps names with dots and underscores treated as equal (upperarm.l and upperarm_l match), so meshes and bases from the same pack line up even when their bone order differs. Two things still go wrong:
- A mesh whose bone names do not exist on the base cannot bind; those vertices follow the wrong bone or none. Make sure the skeleton you extract for the base comes from the same rig family as the meshes that will use it.
- A mesh whose bone rest poses differ from the base's (one pack's large-body variant with a displaced head, for instance) renders offset from what the editor preview shows. The editor previews on the mesh's own skeleton, so it cannot show this. Extract a per-character base from that character's own animation file if it looks wrong in game.
Older content built on the previous player rig (mixamorig_* bone names) keeps working through a legacy bone map to the DEF-* names.
Reference: animations.json#
assets/data/animations.json is client-only; the server never reads it.
{
"version": 1,
"bases": [
{
"id": "humanoid",
"display_name": "humanoid",
"skeleton_path": "assets/skeletons/humanoid_skeleton.tscn",
"animations": [
{
"id": 1,
"name": "idle",
"resource_path": "assets/anims/humanoid/anim_1.tres",
"length_sec": 2.0,
"tags": [],
"retarget_hint": "",
"in_place": false
}
]
}
]
}
Base fields#
| Field | Type | Notes |
|---|---|---|
id | string | Base id NPCs reference (animation_base in npcs.json). Fixed after first save. |
display_name | string | Shown in lists; defaults to the capitalized id. |
skeleton_path | string | Project-relative skeleton scene. |
mesh_path | string | Optional default model set with Set as Base (or by the NPC import flow). |
source_model | string | Optional file name of the model the NPC import flow created the base from. |
default_idle, default_walk, default_run | int | Optional clip ids set from the right-click menu; 0 or absent means none. |
animations | object[] | The clips. |
Clip fields#
| Field | Type | Notes |
|---|---|---|
id | int | Unique within the base. |
name | string | Display name. |
resource_path | string | assets/anims/<base_id>/anim_<id>.tres. |
length_sec | float | Mirrors the resource's length after trim/retime. |
tags | string[] | Searchable labels; the editor preserves them but has no UI to edit them. |
retarget_hint | string | Preserved, not edited. |
in_place | bool | Strip root motion. Default false. |
Paths may be written with or without a res:// prefix; the editor resolves both.
With AI (MCP)#
define_animation_base registers or updates a base (base, display_name, skeleton_path or skeleton_asset_id, optional mesh_path / mesh_asset_id), and define_animation adds a clip to it from an existing .tres (base, name, resource_path or animation_asset_id, length_sec, in_place, optional animation_id). list_animations reads every base and clip back. Neither tool extracts clips from a model file - that still happens in the editor - but they can register clips that are already in the project and wire them to NPCs created with create_npc.
