4.2 KiB
Lottie translation: @remotion/lottie → HF lottie adapter
Lottie animations are a clean translation case — HF has a built-in
Lottie adapter
that supports both lottie-web and @lottiefiles/dotlottie-web. The
adapter auto-discovers animations registered on window.__hfLottie
and seeks them per-frame via goToAndStop.
Pattern
import { Lottie } from "@remotion/lottie";
import animationData from "./hello.json";
export const MyComp = () => (
<AbsoluteFill>
<Lottie animationData={animationData} loop={false} />
</AbsoluteFill>
);
Translates to:
<div id="stage" ...>
<div id="lottie-anim" style="width:100%;height:100%"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.12.2/lottie.min.js"></script>
<script>
const anim = lottie.loadAnimation({
container: document.getElementById("lottie-anim"),
renderer: "svg",
loop: false,
autoplay: false,
path: "assets/hello.json",
});
window.__hfLottie = window.__hfLottie || [];
window.__hfLottie.push(anim);
</script>
</div>
Key differences from a typical Lottie embed:
autoplay: false— HF drives playback by seekingloop: falsetypically (unless Remotion'sloop={true})window.__hfLottie.push(anim)is what hooks the animation into HF's per-frame seek
Asset handling
Remotion bundles the animation JSON via webpack import. HF needs the JSON
on disk under assets/ and references it via path:
- Copy
hello.jsonfrom the Remotion project intohf-src/assets/. - Reference as
path: "assets/hello.json"inloadAnimation.
For dotlottie (binary) format, swap in @lottiefiles/dotlottie-web:
<script src="https://unpkg.com/@lottiefiles/dotlottie-web"></script>
<canvas id="anim" style="width:100%;height:100%"></canvas>
<script>
const player = new DotLottie({
canvas: document.getElementById("anim"),
src: "assets/hello.lottie",
autoplay: false,
});
window.__hfLottie = window.__hfLottie || [];
window.__hfLottie.push(player);
</script>
The HF adapter handles both player APIs (it duck-types goToAndStop
vs setCurrentRawFrameValue / seek).
Multiple Lottie animations
Multiple <Lottie> instances in one composition work — push each one
onto window.__hfLottie and the adapter will seek all of them in sync:
window.__hfLottie.push(anim1);
window.__hfLottie.push(anim2);
window.__hfLottie.push(anim3);
Lottie source isn't actually translation-blocking
Lottie animations encode their own deterministic timeline. They're the easiest part of a Remotion composition to translate because the animation logic is already self-contained — neither Remotion nor HF "animate" them, both just seek them. Translation cost is near-zero.
After Effects → Lottie limitations
Lottie supports a subset of After Effects features. Expressions, most Effects (drop shadow, color overlay), all blend modes beyond Normal/Add/ Multiply, luma mattes, and most 3D parameters are not supported. If the Remotion composition uses a Lottie file that depends on these, the animation will break in BOTH Remotion and HF — this isn't a translation problem, it's a Lottie limitation. See airbnb/lottie/after-effects.md for the full supported feature list.
Loop behavior
Remotion's loop={true} plays the animation continuously. Translate to
the player option only after checking the generated frames. The HF
adapter seeks absolute composition time; it does not add modulo looping
or playback-rate scaling on top of the player. For exact repeating
cycles or non-default playback rates, bake the timing into the Lottie
asset or author an explicit timeline around the Lottie layer and verify
the rendered output.
Performance note
Per the Lottie adapter
docs: lottie-web's goToAndStop(time, isFrame=false) takes time in ms;
the adapter passes time * 1000 for precision. This is more accurate
than passing frame numbers (especially for animations whose internal
fps doesn't match the HF render fps).