Lottie 색상을 코드로 바꾸기 — keypath 완벽 정리
다크모드를 지원하는 순간 모든 Lottie 에셋이 문제가 됩니다. 라이트용·다크용 파일을 두 벌씩 관리할 수도 있지만, 파일 수가 두 배가 되고 디자이너의 수정도 두 배가 됩니다. 정석은 파일은 한 벌, 색은 코드에서 교체하는 것이고, 그 열쇠가 keypath입니다. 이 글은 keypath가 무엇인지, 어떻게 찾는지, 플랫폼별로 어떻게 쓰는지, 그리고 제가 실제로 밟았던 함정들을 정리한 것입니다.
keypath란 — 레이어를 찾아가는 주소
Lottie 애니메이션은 레이어의 트리 구조입니다. keypath는 그 트리에서 특정 속성까지 내려가는 경로 문자열로, 폴더 경로와 비슷하게 생겼습니다. 예를 들어 Heart / Fill 1 / Color는 "Heart 레이어 안의 Fill 1 셰이프의 색상 속성"을 가리킵니다. 중간 단계를 생략하고 싶을 때는 와일드카드를 씁니다.
*— 한 단계 아무거나 (Heart의 바로 아래 자식들)**— 몇 단계든 아무거나 (프리컴프 안까지 전부 탐색)
그래서 실무에서 가장 많이 쓰는 형태는 **.primary_fill.**.Color처럼 "이름이 primary_fill인 레이어를 어디에 있든 찾아서 색을 바꿔라"입니다.
레이어 이름부터 확인하기
keypath를 쓰려면 대상 레이어의 이름을 알아야 합니다. 파일을 Lottie Inspector에 올리면 카드마다 레이어 수가 표시되는데, 이름까지 봐야 한다면 JSON을 직접 열어 "nm" 필드를 찾는 것이 가장 확실합니다. 레이어 이름이 Shape Layer 24 같은 기본값이라면 — 그 파일은 코드로 색을 바꾸기 어려운 파일입니다. 디자이너에게 교체 대상 레이어만이라도 약속된 이름(primary_fill, surface_fill 등)으로 정리해 달라고 요청하는 것이 순서입니다. 이 네이밍 약속 하나가 플랫폼 세 곳의 코드를 전부 안정시킵니다.
플랫폼별 색 교체 코드
웹 (lottie-web)
// SVG 렌더러라면 CSS로도 가능하지만, 정석은 재로드 전 데이터 수정 또는
// 렌더 후 SVG 엘리먼트 선택입니다. 간단한 경우:
document.querySelectorAll('#anim path[fill="#0089A6"]')
.forEach(function (p) { p.setAttribute('fill', newColor); });
lottie-web에는 iOS·Android 같은 공식 동적 속성 API가 없어서, 웹은 SVG DOM을 직접 만지거나 로드 전에 JSON의 색 값을 치환하는 방식을 씁니다. 색 값이 JSON에 [0.0, 0.537, 0.651, 1]처럼 0~1 RGBA 배열로 저장된다는 것만 알면 치환 코드는 단순합니다.
iOS (lottie-ios)
LottieView(animation: .named("spinner"))
.valueProvider(
ColorValueProvider(UIColor.label.lottieColorValue),
for: AnimationKeypath(keypath: "**.primary_fill.**.Color")
)
Android (lottie-compose)
rememberLottieDynamicProperty(
property = LottieProperty.COLOR,
value = MaterialTheme.colorScheme.primary.toArgb(),
keyPath = arrayOf("**", "primary_fill", "**"),
)
Flutter (lottie 패키지)
ValueDelegate.color(const ['**', 'primary_fill', '**'],
value: Theme.of(context).colorScheme.primary)
제가 밟았던 함정 3가지
- 그라디언트는 안 바뀝니다. 단색 Fill의 Color 속성만 이 방식으로 교체됩니다. 그라디언트 스탑을 바꾸려면 플랫폼별 지원이 제각각이라, 그라디언트가 필요한 에셋은 처음부터 테마별 파일 분리가 현실적입니다.
- 프리컴프 안의 레이어는
*로 안 잡힙니다. 한 단계 와일드카드로 시작했다가 프리컴프 중첩 때문에 못 찾는 경우가 흔합니다. 확신이 없으면**로 시작하세요. - 스트로크는 Color가 아니라 별도 속성입니다. 선 색은 Fill이 아니라 Stroke의 Color를 지정해야 합니다. "면은 바뀌는데 테두리가 안 바뀐다"면 십중팔구 이것입니다.
교체가 잘 됐는지는 라이트/다크 배경 위에서 직접 봐야 확실합니다. 뷰어의 배경 전환으로 두 테마 모두 확인한 뒤 통합하세요.