Animations¶
Animations are like cutscenes but without camera tracks, and multiple animations can play simultaneously. Use animations for object movement, UI effects, and anything that doesn't need camera control.
Creating an Animation¶
- Right-click in the Project window -> Create -> PSXSplash -> Animation Clip
- This creates a
PSXAnimationClipScriptableObject - Add it to the Scene Exporter's Animations array
PSXAnimationClip Settings¶
| Field | Description |
|---|---|
| Animation Name | Max 24 chars, unique per scene. Used in Lua: Animation.Play("name") |
| Duration (s) | Total length in seconds. Stored internally as frames at 30fps. |
| Tracks | Array of tracks (Object and UI types only — no Camera, no Audio) |
| Skin Anim Events | Timed triggers for skinned mesh animations (see below) |
Note
If you accidentally add a Camera track to an animation, it will be filtered out with a warning during export.
Track Types¶
Same as cutscene tracks, minus camera:
| Track Type | Target |
|---|---|
| Object Position | Named GameObject |
| Object Rotation | Named GameObject |
| Object Active | Named GameObject (step only) |
| UI Canvas Visible | Named canvas |
| UI Element Visible | Named element |
| UI Progress | Named element |
| UI Position | Named element |
| UI Color | Named element |
| Rumble Small | Controller (global) |
| Rumble Large | Controller (global) |
Lua Playback¶
-- Play one-shot
Animation.Play("door_open")
-- Play with callback
Animation.Play("door_open", {
onComplete = function()
Interact.SetEnabled(self, true)
end
})
-- Play looping
Animation.Play("anim_spinner", {loop = true})
-- Stop by name (stops ALL instances of that animation)
Animation.Stop("anim_spinner")
-- Stop ALL animations
Animation.Stop()
-- Check if any instance is playing
if Animation.IsPlaying("anim_spinner") then
Debug.Log("Still spinning")
end
Skin Anim Events¶
Animations can trigger skinned mesh animations at specific times during playback. This works the same way as cutscene skin anim events.
| Field | Description |
|---|---|
| Time (s) | When to trigger the skinned animation |
| Target Object | Name of the target object (must have a PSXSkinnedObjectExporter) |
| Clip Name | Name of the animation clip on the target |
| Loop | Whether the triggered animation should loop |
-- Example: door animation triggers a character reaction
Animation.Play("door_open", {
onComplete = function()
-- The skin anim event at 0.5s already started the character's
-- "react" animation, so just play the follow-up:
SkinnedAnim.Play("NPC", "idle", { loop = true })
end
})
Note
Skin anim events are processed in frame order. Maximum 16 per animation.
Controller Rumble¶
Animations can drive DualShock controller vibration via two dedicated track types:
| Track | Motor | Values | Behavior |
|---|---|---|---|
| Rumble Small | Right motor (high-frequency) | 0 = off, non-zero = on | Step only — snaps on/off at each keyframe |
| Rumble Large | Left motor (low-frequency) | 0–255 motor speed | Interpolated — smoothly ramps between keyframes |
Rumble tracks are global (no target object needed). Add keyframes to control when and how strongly the controller vibrates during the animation.
Combining motors
Use the small motor for sharp impacts (gunshots, hits) and the large motor for sustained rumble (engines, earthquakes). Combine both for layered effects.
Note
Rumble requires a DualShock controller (or emulator rumble support). Digital controllers ignore vibration data.
Multi-Instance Playback¶
Unlike cutscenes, the same animation can play multiple times simultaneously. Each Animation.Play() call creates a new playback instance. Up to 8 instances can be active at once across all animations.
-- These create two separate instances, both playing at once
Animation.Play("particle_burst")
Animation.Play("particle_burst")
Animation.Stop("name") stops all instances of that animation.
Callback Behavior¶
The onComplete callback is stored per animation name, not per instance. If the same animation is playing multiple times, the callback fires when any instance of it finishes (and only once per stop, not per-loop).
Limits¶
| Resource | Limit |
|---|---|
| Animation clips per scene | 16 |
| Tracks per animation | 8 |
| Keyframes per track | 64 |
| Skin anim events per animation | 16 |
| Simultaneous instances | 8 (across all animations) |
Time-Based Playback¶
Animations use time-based advancement internally (0.12 fixed-point delta time). This means playback speed is consistent regardless of the actual framerate — if the engine dips below 30fps, animations continue at the correct speed rather than slowing down.
The editor displays all timing in seconds. Internally, 30fps frames are used for storage (e.g., 3 seconds = 90 frames).
Editor Preview¶
Animations can be edited in the PSX Timeline editor window (PlayStation 1 > Timeline Editor from the menu, or double-click an animation clip asset). The timeline provides:
- A visual track layout showing all keyframe tracks and skin anim events
- Drag-and-drop keyframe editing with interpolation mode selection
- Play/scrub controls to preview the animation in the Scene view
- If the animation has skin anim events, targeted skinned meshes show the correct pose at the current time
You can also preview directly from the animation inspector by clicking the play button.