Xocoatl — UI Animator
Keyframe timelines, easing, optional 2D UI particles, a tiny runtime, colour picker, and layout tools — polish your Studio UI without fighting the property panel.
I’ve been building this for a long time — lots of rewrites and “one more fix” before posting. It’s here now and I’m genuinely happy with where it landed.
Below is everything the plugin does today, so this thread stays a single place to see what you’re getting.
Timeline Animator

The core workflow: set an animation target → open or create a clip → add elements from the Hierarchy → add property tracks → keyframe on the timeline → preview → save.
-
Edits run on a preview clone (
StarterGui/_UIAnimPreview) so your real UI isn’t touched until you close the animation and test in-game. -
Always close the animation before pressing Play in Studio — otherwise the clone can show up in the running game.
Tracks, keyframes & easing
-
One row per element; [+] opens a searchable property picker (Position, Size, Rotation, transparency, colours,
UIGradientsequences, booleans like Visible/Enabled, and more — see docs for the full list). -
Per-keyframe easing — right‑click a diamond: Linear, Quad, Sine, Back, Bounce, Elastic, etc., with In / Out / InOut and a small curve preview.
-
Delta mode on any property track — keyframes become offsets from the starting value, so one clip can reuse on different buttons or slots without fixed coordinates.
-
Compound sub-rows — expand Position / Size / Colour tracks for per-component control (e.g. axes or RGB).
-
Multi-select workflows for keyframes and compatible tracks; Edit → Copy / Paste Keyframes for time-based clipboard workflows.
Colour & effects
-
Colour swatches on Color3 tracks open the integrated colour picker (same preset/palette system as the standalone picker).
-
Screen effects — animate BlurEffect, ColorCorrectionEffect, BloomEffect, Camera FOV, etc. The runtime can create and tear these down for you.
2D particle system (experimental)
-
On supported hosts (Frame, ImageButton, ImageLabel, TextLabel, TextButton, CanvasGroup): element row ⋮ → Make Particle Frame.
-
Particle rows live on the same timeline as the rest of the UI — rate, lifetime, speed, spread, texture, emission edge, optional Motion / Velocity inheritance, lifetime Size / Transparency sequences (Seq editor with optional live preview), and more.
-
Emit container — ScreenGui (full-screen particle layer) or Emitter (parent under the frame for clipping/stacking with that UI).
-
Clip-wide options (Track list Particles block + Animation menu):
-
Keep particles emitting after clip ends — after a forward finish, particles can keep spawning at the last sampled time until you stop that playback key or clear the instance.
-
No particle emit on reverse — hover-out / reversed playback stops new spawns; existing particles age out (great for menu polish).
Particles are experimental — behaviour and defaults may evolve; still great for prototyping and shipped UI once you’ve tested your build.


Authoring & workflow extras
-
Template animation — design a clip without locking it to one saved UI root; at runtime use
{ target = guiObject }orAnim.playOnso one clip drives many instances (menus, inventory slots, cards). -
Timeline events — place named markers on the ruler (right‑click ruler → place event); fire
onEventin Lua when playback crosses them. -
Clip folders / saves browser — organise animations under
ReplicatedStorage/ChocosToolsSaves/SavedUIAnimations; multi-select moves in the browser where supported. -
Export UI + Animation / Import UI + Animation — bundle UI + clip for sharing or moving between places (File menu).
-
Preview in Container — try the clip inside another ScreenGui context when you need it.
-
Undo / redo — full stack for keyframes, tracks, hierarchy changes, easing, and more.
Playing animations in-game (runtime)
Install once from the Timeline landing screen (Install / Update Runtime) → scripts land under StarterPlayerScripts/Xocoatl.
local Anim = require(
game.Players.LocalPlayer.PlayerScripts.Xocoatl.UIAnimController
)
Anim.play("ShopOpen")
-- Same clip backwards — open once, close for free
Anim.play("ShopOpen", { reverse = true })
Anim.play("IdleFloat", { loop = true })
Anim.play("Intro", { delay = 3 })
Anim.play("ClickPop", { reset = true })
-- Ping-pong, loop counts, speed — all supported
Anim.play("Breathe", { loop = true, pingpong = true })
local handle = Anim.play("SlideIn")
handle.pause()
handle.resume()
handle.scrub(0.5)
handle.stop()
Highlights:
| API | What it’s for |
|-----|----------------|
| Anim.playOn(inst, "Clip") | Clip was authored as template or you want a different root than the saved target. |
| Anim.play("Clip", { target = inst }) | Same idea — explicit override. |
| Anim.bindHover(btn, "HoverClip") | MouseEnter forward / MouseLeave reversed — one line hover polish. |
| Anim.bindButton(btn, hover?, click?, opts?) | Hover + click clips with sensible keys and optional resume behaviour. |
| Anim.playBatch(list, "Clip", { stagger = 0.06 }) | Lists, grids, cascaded reveals. |
| Anim.sequence({ { name = "A" }, { name = "B" } }) | Chain clips without nesting callbacks. |
| Anim.clearInstance(frame) | Stop everything targeting that UI root before hiding/destroying it. |
| Anim.stopOn(inst, "Clip") | Stop a named clip bound to an instance. |
| onEvent / events | React to timeline markers or scripted time callbacks. |
| Handles | Completed, Cancelled, MarkerReached, Looped signals alongside options. |
Particles in clips — if the saved clip has particle tracks, Anim.play runs the same simulator as the editor: tails drain on interrupt when possible (no hard pop), with the clip flags above controlling post-end emission and reverse behaviour.
Hierarchy explorer
Left panel: full tree under the animation target, search filter, collapse/expand with L on selection, Add From Selected (Explorer multi-select → one click into the Track List).
UI Tools dock

Open Tools from the toolbar — six draggable slots. Pick from:
-
Align — 3×3 AnchorPoint + Position grid; multi-instance.
-
Simple Move — nudge by scale or offset step.
-
Color Presets — apply saved presets (Background / Text / Image / gradients via UIGradient); palettes sync with the Colour Picker.
-
Rich Text — WYSIWYG for TextLabel / TextButton / TextBox (bold, italic, underline, colours, stroke, etc.).
-
Conversion — Scale ↔ Offset for Size/Position; aspect constraint helpers.
-
UI Converter — reparent-friendly class swaps (Frame ↔ ImageLabel, etc.).
-
Copy Path — dot-separated Explorer path for scripts.
Xocoatl features (from the Tools dock) — optional overlays such as a viewport selection breadcrumb; off by default.
Colour Picker (standalone)
Third toolbar button — full picker + palettes / presets shared with timeline colour tracks and Color Presets in Tools.
Docs & support
Documentation — runtime API, particles guide, delta mode, templates, hover, batch/sequence patterns, install steps. Community: Discord.
If something’s confusing or missing, tell me and I’ll extend the docs.
This is a solo project — bugs and rough edges are possible. Options → Report in the plugin links to GitHub for bugs and feature requests, or reply here.
Thanks for sticking with it since the early previews. Hope it saves you time.
Chocobasta out ![]()

