install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/lottie" ~/.claude/skills/comeonoliver-skillshub-lottie && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/lottie/SKILL.mdsource content
Lottie
Render After Effects animations exported as JSON. Lightweight, scalable, and interactive.
Setup
# Install lottie-web for vanilla JS/TS projects. npm install lottie-web
Basic Playback
// src/lottie/player.ts — Load and play a Lottie animation in a DOM container. // The animation JSON is typically exported from After Effects via Bodymovin. import lottie, { AnimationItem } from "lottie-web"; export function playAnimation( container: HTMLElement, animationData: object ): AnimationItem { return lottie.loadAnimation({ container, renderer: "svg", // "canvas" or "html" also available loop: true, autoplay: true, animationData, }); } // Load from URL instead of inline data export function playFromUrl(container: HTMLElement, path: string): AnimationItem { return lottie.loadAnimation({ container, renderer: "svg", loop: true, autoplay: true, path, // URL to the JSON file }); }
Playback Controls
// src/lottie/controls.ts — Control animation playback: play, pause, seek, speed. import type { AnimationItem } from "lottie-web"; export function setupControls(anim: AnimationItem) { // Play / Pause anim.play(); anim.pause(); anim.stop(); // Go to specific frame (frame 30, and play) anim.goToAndPlay(30, true); // Go to specific frame and stop anim.goToAndStop(0, true); // Playback speed (2x) anim.setSpeed(2); // Play direction (-1 = reverse) anim.setDirection(-1); // Play only a segment (frames 10-50) anim.playSegments([10, 50], true); }
Event Handling
// src/lottie/events.ts — Listen to animation lifecycle events for triggering // UI updates, chaining animations, or tracking analytics. import type { AnimationItem } from "lottie-web"; export function attachEvents(anim: AnimationItem) { anim.addEventListener("complete", () => { console.log("Animation completed"); }); anim.addEventListener("loopComplete", () => { console.log("Loop finished"); }); anim.addEventListener("enterFrame", (e) => { // Fires every frame — use sparingly const progress = (e as any).currentTime / anim.totalFrames; document.getElementById("progress")!.style.width = `${progress * 100}%`; }); anim.addEventListener("DOMLoaded", () => { console.log("Animation DOM elements ready"); }); }
React Integration
// src/components/LottiePlayer.tsx — React component wrapping lottie-web. // Handles cleanup on unmount and exposes ref for external control. import { useEffect, useRef } from "react"; import lottie, { AnimationItem } from "lottie-web"; interface Props { animationData: object; loop?: boolean; autoplay?: boolean; className?: string; } export function LottiePlayer({ animationData, loop = true, autoplay = true, className }: Props) { const containerRef = useRef<HTMLDivElement>(null); const animRef = useRef<AnimationItem | null>(null); useEffect(() => { if (!containerRef.current) return; animRef.current = lottie.loadAnimation({ container: containerRef.current, renderer: "svg", loop, autoplay, animationData, }); return () => { animRef.current?.destroy(); }; }, [animationData, loop, autoplay]); return <div ref={containerRef} className={className} />; }
Dynamic Color Updates
// src/lottie/theme.ts — Modify colors inside a Lottie JSON before rendering. // Useful for theming animations to match brand colors at runtime. export function recolorAnimation( animationData: any, colorMap: Record<string, [number, number, number]> ): any { const data = JSON.parse(JSON.stringify(animationData)); function walkShapes(shapes: any[]) { for (const shape of shapes) { if (shape.ty === "fl" && shape.c?.k) { const hex = rgbToHex(shape.c.k[0], shape.c.k[1], shape.c.k[2]); if (colorMap[hex]) { const [r, g, b] = colorMap[hex]; shape.c.k = [r, g, b, 1]; } } if (shape.it) walkShapes(shape.it); } } for (const layer of data.layers || []) { if (layer.shapes) walkShapes(layer.shapes); } return data; } function rgbToHex(r: number, g: number, b: number): string { return "#" + [r, g, b].map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join(""); }