text-to-lottie▌
diffusionstudio/lottie · updated Jun 9, 2026
MDX-style export adds YAML metadata + attribution linking explainx.ai and this canonical listing URL.
Create and edit Lottie animations using Skia's Skottie module.
| name | text-to-lottie |
| description | Author a Lottie (Bodymovin) JSON animation that renders in a local skia player. Use whenever the user asks to create, generate, edit, or fix a Lottie animation, or asks for "an animation" to load. |
Authoring Renderable Lottie Files
This app renders Lottie with Skia's Skottie module (via canvaskit-wasm),
not the JS lottie-web runtime. Follow the rules below and
verify the result.
This skill covers the mechanics — the JSON shape Skottie needs. For the craft (timing, easing, choreography, Disney animation principles), see LottieFiles' motion-design skill. Its guidance is in milliseconds; convert to frames with
frames = ms / 1000 * fr.
Setting up the project
The deliverable is not just public/lottie.json: the viewer should be set up
and the animation should be previewable in the browser. If the player project is
missing, create it; if it exists, install/update dependencies as needed, start
the dev server, and open the local preview URL for verification.
Always use the official GitHub player project — never hand-roll a custom
viewer. This skill's JSON rules (slots, the properties panel, the ?frame=
URL controls, the Skottie wasm wiring) only hold inside that exact project. Do
not build your own HTML page, swap in lottie-web, or scaffold a bespoke
canvas setup — any of those will silently diverge from how this player renders
and the verification steps below won't apply. If the player project isn't
already on this machine, scaffold a fresh copy of the repo with degit:
npx degit diffusionstudio/lottie my-animation
cd my-animation
npm install # postinstall copies the CanvasKit wasm into /public
npm run dev
Then open the printed local URL. If you already have the project, just
npm install && npm run dev.
Where to write the file (and how it loads)
- Write the animation JSON to
public/lottie.json. That is the only file you need to touch to change what the app shows —src/App.tsxfetches/lottie.jsonat startup. - With the dev server running (
npm run dev), a Vite plugin watches that file and full-reloads the page on save, so your edit appears immediately. No other wiring is required. - If parsing fails, the app shows the error on screen ("CanvasKit could not parse the Lottie file.").
Required top-level shape
Every Lottie document is one JSON object with at least these fields:
{
"v": "5.7.0", // bodymovin version string
"fr": 60, // frame rate (fps)
"ip": 0, // in point (start frame)
"op": 120, // out point (end frame) — duration = (op - ip) / fr seconds
"w": 512, // composition width (px)
"h": 512, // composition height (px)
"assets": [], // images / precomps; [] if none
"layers": [ /* ... */ ]
}
The app letterboxes the w×h composition to fit the canvas, so pick a square
or sensible aspect ratio. op controls the total frame count shown in the UI.
Layers
layers follows After Effects order: the first entry in the array is the
topmost layer, and later entries render underneath it. Each layer needs at
minimum:
{
"ty": 4, // layer type: 4 = shape layer (the common case)
"nm": "circle", // name (optional but helpful)
"ip": 0, // layer in point
"op": 120, // layer out point — must cover the frames you want it visible
"st": 0, // start time
"ks": { /* transform — see below */ },
"shapes": [ /* ... */ ] // for shape layers
}
Common layer types: 4 shape, 2 image, 1 solid, 0 precomp, 5 text.
Prefer shape layers (ty: 4) for LLM-authored animations — no external
assets needed.
The transform block (ks)
Every layer has a transform. Each property is either static ({ "a": 0, "k": value })
or animated ({ "a": 1, "k": [ ...keyframes ] }).
"ks": {
"o": { "a": 0, "k": 100 }, // opacity 0–100
"r": { "a": 0, "k": 0 }, // rotation (degrees)
"p": { "a": 0, "k": [256, 256, 0] }, // position [x, y, z]
"a": { "a": 0, "k": [0, 0, 0] }, // anchor point [x, y, z]
"s": { "a": 0, "k": [100, 100, 100] } // scale (percent, per axis)
}
Anchor matters: rotation and scale pivot around the anchor a, expressed in
the layer's own coordinate space. To rotate a shape around its own center, set
the shape's geometry around the anchor (e.g. center the ellipse on a).
Shapes — the #1 Skottie gotcha
Skottie requires shape elements to be wrapped in a Group (ty: "gr"). A flat
list of shapes + fills directly in shapes renders blank. Always nest the
geometry, fill/stroke, and a group transform inside a group's it array:
"shapes": [
{
"ty": "gr", // GROUP — required wrapper
"nm": "ball",
"it": [
{
"ty": "el", // ellipse
"p": { "a": 0, "k": [0, 0] },
"s": { "a": 0, "k": [120, 120] }
},
{
"ty": "fl", // fill
"c": { "a": 0, "k": [0.2, 0.6, 1, 1] }, // RGBA, each 0–1
"o": { "a": 0, "k": 100 }
},
{
"ty": "tr", // GROUP TRANSFORM — include even if identity
"p": { "a": 0, "k": [0, 0] },
"a": { "a": 0, "k": [0, 0] },
"s": { "a": 0, "k": [100, 100] },
"r": { "a": 0, "k": 0 },
"o": { "a": 0, "k": 100 }
}
]
}
]
Shape primitives inside it:
"el"ellipse —pcenter,s[width, height]"rc"rectangle —pcenter,s[w, h],rcorner radius"sh"custom path —ks.kis a bezier{ "c": closed?, "v": verts, "i": inTangents, "o": outTangents }"st"stroke —ccolor,wwidth,oopacity"fl"fill —ccolor (RGBA 0–1),oopacity"tr"the group's transform (always include it last)
Colors are normalized 0–1 RGBA, not 0–255. [1, 0, 0, 1] is opaque red.
Animating a property (keyframes)
Set "a": 1 and make k an array of keyframe objects. Each keyframe has a
time t (frame), a value s (start value for that segment, as an array), and
easing handles i/o:
"p": {
"a": 1,
"k": [
{ "t": 0, "s": [256, 120], "i": { "x": [0.5], "y": [1] }, "o": { "x": [0.5], "y": [0] } },
{ "t": 60, "s": [256, 400], "i": { "x": [0.5], "y": [1] }, "o": { "x": [0.5], "y": [0] } },
{ "t": 120, "s": [256, 120] }
]
}
tis the frame number; the last keyframe usually has noi/o/easing pair beyonds(it's the end).sis always an array, even for scalars like rotation:"s": [360].i/oare the bezier ease handles (incoming / outgoing).x/yarrays in[0..1]. For a smooth ease usex:[0.5], y:[1](in) andx:[0.5], y:[0](out); for linear usex:[0], y:[0]/x:[1], y:[1]. Multi-dimensional values may use per-axis arrays.- To loop seamlessly, make the last keyframe's value equal the first.
Exposing editable properties (slots + the properties panel)
The app can render a live properties panel (text inputs and sliders) that edit chosen values of the animation in real time. This rides on Skottie's native slot feature — no re-parse, the change shows on the next frame.
To make a property editable, do two things:
1. Declare a slot in the Lottie JSON. Add a top-level "slots" object whose
keys are slot IDs, and point a property at one with "sid" instead of (or
alongside) an inline value. The slot's "p" holds the default, in the same
shape the property would normally take.
{
"v": "5.7.0", "fr": 60, "ip": 0, "op": 90, "w": 512, "h": 512, "assets": [],
"slots": {
"ballColor": { "p": { "a": 0, "k": [0.231, 0.6, 1, 1] } }, // color: RGBA 0–1
"ballSize": { "p": { "a": 0, "k": 120 } } // scalar
},
"layers": [ /* ... */
// in the fill: "c": { "sid": "ballColor" }
// in a scalar: "s": { "sid": "ballSize" }
]
}
Slot types map to controls like this:
| Slot value | Control rendered |
|---|---|
| scalar (a single number) | slider |
| color (RGBA 0–1) | color picker |
vec2 ([x, y]) | two number inputs |
| text (a string) | text input |
The app discovers slots automatically via Skottie's getSlotInfo() — you do
not list them anywhere else for them to work. The panel appears as soon as
the animation declares at least one slot.
Required: a background-color control on every animation
Every animation you produce must expose at least one control for the
background color. The player does not paint a composition background of its
own, so add a full-composition background layer as the last entry in
layers (so it renders underneath everything), fill it with a slotted color,
and label that slot in controls.json. Use a rectangle the size of the
composition:
// last layer in `layers`:
{
"ty": 4, "nm": "background", "ip": 0, "op": 120, "st": 0,
"ks": { "o": { "a": 0, "k": 100 }, "p": { "a": 0, "k": [256, 256, 0] },
"a": { "a": 0, "k": [0, 0, 0] }, "s": { "a": 0, "k": [100, 100, 100] },
"r": { "a": 0, "k": 0 } },
"shapes": [
{ "ty": "gr", "it": [
{ "ty": "rc", "p": { "a": 0, "k": [256, 256] },
"s": { "a": 0, "k": [512, 512] }, "r": { "a": 0, "k": 0 } },
{ "ty": "fl", "c": { "sid": "bgColor" }, "o": { "a": 0, "k": 100 } },
{ "ty": "tr", "p": { "a": 0, "k": [0, 0] }, "a": { "a": 0, "k": [0, 0] },
"s": { "a": 0, "k": [100, 100] }, "r": { "a": 0, "k": 0 },
"o": { "a": 0, "k": 100 } }
] }
}
// slots: "bgColor": { "p": { "a": 0, "k": [1, 1, 1, 1] } } // default white
// controls: { "sid": "bgColor", "label": "Background color" }
Match the rectangle's p/s to your composition's w×h. This is in addition
to whatever other controls the animation exposes.
2. (Optional) Describe presentation in public/controls.json. Slots only
expose an ID and type, not a label or a sensible slider range. The sidecar file
adds that. It is optional — missing entries fall back to the slot ID and a
generic 0–100 range. Like lottie.json, it hot-reloads on save.
{
"controls": [
{ "sid": "ballColor", "label": "Ball color" },
{ "sid": "ballSize", "label": "Ball size", "min": 40, "max": 240, "step": 1 }
]
}
sidmust match a slot ID exactly.labelis the display name;min/max/stepshape scalar sliders and vec2 inputs (ignored for color/text).- An entry whose
sidmatches no slot is simply ignored; a slot with no entry still renders with defaults.
Controlling playback from a browser agent
When you drive the page through a browser tool, do not pixel-drag the slider or hunt for the play button — it's unreliable and you can't land on an exact frame. Instead, pin the frame in the URL and read the canvas by its test id:
http://localhost:5173/?frame=60&paused=1
?frame=Nseeks to frameNon load and holds it paused, so the moment sits still for a screenshot. This is the right way to inspect a specific frame (e.g. "is the ball at the bottom at frame 60?"): open?frame=60, then screenshot.?paused=1starts paused (at frame 0, or atframeif also given);?paused=0forces autoplay even with a frame pinned.- With no query params the animation autoplays as usual.
To change the inspected frame, navigate to a new URL (or just edit the query
string and reload). The canvas carries data-testid="lottie-canvas", so a
browser tool can target it directly for screenshots. If the canvas is blank,
the page hasn't finished loading or the Lottie failed to parse (check the
on-screen error).
Before you finish — checklist
- The file is valid JSON (no comments, no trailing commas). Validate with
node -e "JSON.parse(require('fs').readFileSync('public/lottie.json','utf8'))". - Every shape primitive/fill is inside a
"ty": "gr"group'sitarray, and each group ends with a"tr"transform. - Top-level
opand each layer'sopcover the frames you animate. - Colors are 0–1 RGBA; positions/sizes are within the
w×hcomposition. - Keyframe
svalues are arrays; loops repeat the first value at the end. - A background-color control is present: a full-composition background layer
(last in
layers) with a slotted fill (e.g.bgColor) and a matchingcontrols.jsonlabel. - The project is the official GitHub player (scaffolded via degit), not a custom/hand-rolled viewer.
- If the dev server is running, just save — it hot-reloads. Otherwise start it
with
npm run dev. A blank canvas (no error) → re-check the group wrapping. - The player is running and the preview URL has been opened or reported. When a
browser tool is available, verify the page shows a nonblank rendered
animation before finalizing — pin a key frame via the URL (see "Controlling
playback from a browser agent"), e.g. open
?frame=60&paused=1and screenshot, rather than dragging the on-screen slider.
How to use text-to-lottie on Cursor
AI-first code editor with Composer
Prerequisites
Before installing skills in Cursor, ensure your development environment meets these requirements:
- ›Cursor installed and configured on your development machine
- ›Node.js version 16.0+ with npm package manager (verify with
node --version) - ›Active project directory or workspace where you want to add text-to-lottie
Execute installation command
Execute the skills CLI command in your project's root directory to begin installation:
The skills CLI fetches text-to-lottie from GitHub repository diffusionstudio/lottie and configures it for Cursor.
Select Cursor when prompted
The CLI will show a list of available agents. Use arrow keys to navigate and space to select Cursor:
Verify installation
Confirm successful installation by checking the skill directory location:
Reload or restart Cursor to activate text-to-lottie. Access the skill through slash commands (e.g., /text-to-lottie) or your agent's skill management interface.
Security & Verification Notice
We perform automated surface-level scans (Gen AI Scanner, Socket, Snyk) during installation. These checks detect common vulnerabilities but do not guarantee complete security. Always review skill source code and verify the publisher's reputation before production use.
Skills execute code in your development environment. Always verify the publisher's identity, review recent commits, and test in isolated environments before production deployment.
List & Monetize Your Skill
Submit your Claude Code skill and start earning
Use Cases▌
Task Automation & Efficiency
Automate repetitive workflows and reduce manual effort
Example
Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Knowledge Enhancement
Learn new skills, understand complex topics, get expert guidance
Example
Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Quality Improvement
Enhance output quality through reviews, suggestions, and refinements
Example
Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
Implementation Guide▌
Prerequisites
- ›Claude Desktop or compatible AI client with skill support
- ›Clear understanding of task or problem to solve
- ›Willingness to iterate and refine outputs
Time Estimate
15-45 minutes depending on use case complexity
Installation Steps
- 1.Install skill using provided installation command
- 2.Test with simple use case relevant to your work
- 3.Evaluate output quality and relevance
- 4.Iterate on prompts to improve results
- 5.Integrate into regular workflow if valuable
Common Pitfalls
- ⚠Expecting perfect results without iteration
- ⚠Not providing enough context in prompts
- ⚠Using skill for tasks outside its intended scope
- ⚠Accepting outputs without review and validation
Best Practices▌
✓ Do
- +Start with clear, specific prompts
- +Provide relevant context and constraints
- +Review and refine all outputs before using
- +Iterate to improve output quality
- +Document successful prompt patterns
✗ Don't
- −Don't use without understanding skill limitations
- −Don't skip validation of outputs
- −Don't share sensitive information in prompts
- −Don't expect skill to replace human judgment
💡 Pro Tips
- ★Be specific about desired format and style
- ★Ask for multiple options to choose from
- ★Request explanations to understand reasoning
- ★Combine AI efficiency with human expertise
When to Use This▌
✓ Use When
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid When
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
Learning Path▌
- 1Familiarize yourself with skill capabilities and limitations
- 2Start with low-risk, non-critical tasks
- 3Progress to more complex and valuable use cases
- 4Build expertise through regular use and experimentation
Discussion
Product Hunt–style comments (not star reviews)- No comments yet — start the thread.
Ratings
4.7★★★★★61 reviews- ★★★★★Michael Patel· Dec 28, 2024
text-to-lottie has been reliable in day-to-day use. Documentation quality is above average for community skills.
- ★★★★★Fatima Ghosh· Dec 28, 2024
text-to-lottie is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
- ★★★★★Ganesh Mohane· Dec 12, 2024
Useful defaults in text-to-lottie — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
- ★★★★★Hana Lopez· Dec 12, 2024
I recommend text-to-lottie for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
- ★★★★★Ira Martinez· Dec 12, 2024
Solid pick for teams standardizing on skills: text-to-lottie is focused, and the summary matches what you get after install.
- ★★★★★Michael Sanchez· Nov 19, 2024
Useful defaults in text-to-lottie — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
- ★★★★★Evelyn Perez· Nov 19, 2024
text-to-lottie reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Naina Flores· Nov 15, 2024
text-to-lottie fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
- ★★★★★Rahul Santra· Nov 3, 2024
text-to-lottie has been reliable in day-to-day use. Documentation quality is above average for community skills.
- ★★★★★Fatima Dixit· Nov 3, 2024
Solid pick for teams standardizing on skills: text-to-lottie is focused, and the summary matches what you get after install.
showing 1-10 of 61