Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/core/src/runtime/adapters/lottie.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,27 @@ describe("lottie adapter", () => {
adapter.seek({ time: -5 });
expect(anim.goToAndStop).toHaveBeenCalledWith(0, false);
});

it("seeks a v1 dotlottie player by percentage when duration is known", () => {
// v1 player: has seek() but no setCurrentRawFrameValue.
const seek = vi.fn();
const player = { play: vi.fn(), pause: vi.fn(), duration: 4, seek };
lottieWindow.__hfLottie = [player];
const adapter = createLottieAdapter();
adapter.seek({ time: 1 }); // 1 / 4 * 100 = 25
expect(seek).toHaveBeenCalledWith(25);
});

it("does not seek a v1 dotlottie player whose duration is 0 (not yet loaded)", () => {
// duration 0 before load: an unguarded (time / 0) * 100 = NaN used to
// reach seek() and blank the first frame at composition time 0.
const seek = vi.fn();
const player = { play: vi.fn(), pause: vi.fn(), duration: 0, seek };
lottieWindow.__hfLottie = [player];
const adapter = createLottieAdapter();
adapter.seek({ time: 0 });
expect(seek).not.toHaveBeenCalled();
});
});

describe("pause", () => {
Expand Down
14 changes: 10 additions & 4 deletions packages/core/src/runtime/adapters/lottie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,16 @@ export function createLottieAdapter(): RuntimeDeterministicAdapter {
anim.setCurrentRawFrameValue(Math.min(frame, totalFrames - 1));
}
} else if (typeof anim.seek === "function") {
// dotlottie-web v1: seek(percentage 0-100)
const duration = anim.duration ?? 1;
const percentage = Math.min(100, (time / duration) * 100);
anim.seek(percentage);
// dotlottie-web v1: seek(percentage 0-100). Mirror the v2 guard
// above: a not-yet-loaded player reports duration 0, and `0 ?? 1`
// stays 0 (nullish coalescing does not replace 0), so an unguarded
// (time / 0) * 100 = NaN reached seek() and blanked the first frame
// at composition time 0.
const duration = anim.duration ?? 0;
if (duration > 0) {
const percentage = Math.max(0, Math.min(100, (time / duration) * 100));
anim.seek(percentage);
}
}
}
} catch (err) {
Expand Down
Loading