Theme Specification
Complete technical specification for dotLottie dynamic theming
Theme Specification
Dynamic theming enables runtime customization of Lottie animations by overriding animated property values without modifying the original animation file.
Version
Current specification version: 1.0
Overview
Themes are JSON files stored in the t/ directory of a .lottie archive. Each theme file contains an array of rules that override specific animated properties. Rules target properties by their Lottie Slot ID — only properties that have been assigned a slot ID in the Lottie animation can be themed.
Use Cases
Light/dark mode switching
Brand color customization
Accessibility adjustments (high contrast)
Seasonal or contextual styling
File Location
Theme files are stored in the t/ directory and referenced from the manifest:
{
"version": "2",
"animations": [
{
"id": "my_animation",
"initialTheme": "light",
"themes": ["light", "dark"]
}
],
"themes": [
{ "id": "light", "name": "Light Theme" },
{ "id": "dark", "name": "Dark Theme" }
]
}The id values correspond to files in the archive: "light" → t/light.json.
Theme File Format
A theme file is a JSON object with a single rules array:
| Field | Required | Type | Description |
rules | Yes | Rule[] | List of property overrides. Each entry targets exactly one slotted Lottie property. |
Example Theme File
{
"rules": [
{
"id": "background_color",
"type": "Color",
"value": [0.12, 0.12, 0.12]
},
{
"id": "icon_opacity",
"type": "Scalar",
"value": 80
},
{
"id": "brand_color",
"type": "Color",
"animations": ["animation_01"],
"value": [0.0, 0.48, 1.0]
}
]
}Rule
A rule targets a specific slotted property in a Lottie animation.
| Field | Required | Type | Description |
id | Yes | String | Slot ID of the property to override. Case-sensitive. |
type | Yes | "Color" | "Scalar" | "Position" | "Vector" | "Gradient" | "Image" | "Text" | The rule type, matching the Lottie property type being overridden. |
animations | No | string[] | Limit the rule to specific animations by ID. If omitted, the rule applies to all animations. |
value | Yes* | See per-type tables below | Static override value. Required if keyframes is not provided. |
keyframes | Yes* | Type-specific Keyframe objects | Animated override. Required if value is not provided. Takes precedence over value. |
expression | No | String | Lottie expression for dynamic values. Takes precedence over value and keyframes. |
* Either value or keyframes must be provided, but not both.
Rule Types
Color Rule
Overrides color properties (fill color, stroke color, text color).
| Field | Type | Description |
value | [R, G, B] (0–1 normalized per channel) | Static color. e.g. [1, 0, 0] for red. |
keyframes | Color Keyframe[] | Animated color transitions. |
Color Keyframe
| Field | Required | Type | Description |
frame | Yes | Number | Animation frame number where this color is applied. |
value | Yes | [R, G, B] (0–1 normalized) | Color at this keyframe. |
inTangent | No | { x: number|number[], y: number|number[] } | Incoming Bézier easing handle. |
outTangent | No | { x: number|number[], y: number|number[] } | Outgoing Bézier easing handle. |
hold | No | Boolean | If true, hold value without interpolating. |
Example: Static Color
{
"id": "fill_color",
"type": "Color",
"value": [0.0, 0.47, 1.0]
}Example: Animated Color
{
"id": "background",
"type": "Color",
"keyframes": [
{ "frame": 0, "value": [1, 1, 1] },
{ "frame": 30, "value": [0.12, 0.12, 0.12] }
]
}Scalar Rule
Overrides single-value numeric properties (opacity, stroke width, rotation, etc.).
| Field | Type | Description |
value | Number | Static numeric value. |
keyframes | Scalar Keyframe[] | Animated numeric values over time. |
Scalar Keyframe
| Field | Required | Type | Description |
frame | Yes | Number | Animation frame number. |
value | Yes | Number | Numeric value at this keyframe. |
inTangent | No | { x: number|number[], y: number|number[] } | Incoming Bézier easing handle. |
outTangent | No | { x: number|number[], y: number|number[] } | Outgoing Bézier easing handle. |
hold | No | Boolean | If true, hold value without interpolating. |
Example
{
"id": "icon_opacity",
"type": "Scalar",
"value": 75
}Position Rule
Overrides position properties (position, anchor point, gradient start/end point).
| Field | Type | Description |
value | [x, y] or [x, y, z] | Static position coordinates. |
keyframes | Position Keyframe[] | Animated position over time. |
Position Keyframe
| Field | Required | Type | Description |
frame | Yes | Number | Animation frame number. |
value | Yes | [x, y] or [x, y, z] | Position at this keyframe. |
inTangent | No | { x: number|number[], y: number|number[] } | Incoming Bézier easing handle. |
outTangent | No | { x: number|number[], y: number|number[] } | Outgoing Bézier easing handle. |
hold | No | Boolean | If true, hold value without interpolating. |
valueInTangent | No | Number[] | Tangent for curved path movement. |
valueOutTangent | No | Number[] | Tangent for curved path movement. |
Example
{
"id": "element_position",
"type": "Position",
"value": [100, 200]
}Vector Rule
Overrides vector properties (scale, size).
| Field | Type | Description |
value | [x, y] | Static vector value. |
keyframes | Vector Keyframe[] | Animated vector over time. |
Vector Keyframe
| Field | Required | Type | Description |
frame | Yes | Number | Animation frame number. |
value | Yes | [x, y] | Vector at this keyframe. |
inTangent | No | { x: number|number[], y: number|number[] } | Incoming Bézier easing handle. |
outTangent | No | { x: number|number[], y: number|number[] } | Outgoing Bézier easing handle. |
hold | No | Boolean | If true, hold value without interpolating. |
Example
{
"id": "icon_scale",
"type": "Vector",
"value": [1.5, 1.5]
}Gradient Rule
Overrides gradient properties with a list of color stops.
| Field | Type | Description |
value | Gradient Stop[] | Static gradient color stops. |
keyframes | Gradient Keyframe[] | Animated gradient over time. |
Gradient Stop
| Field | Required | Type | Description |
color | Yes | [R, G, B] (0–1 normalized) | Color at this stop. |
offset | Yes | Number (0–1) | Stop position along the gradient (0 = start). |
Gradient Keyframe
| Field | Required | Type | Description |
frame | Yes | Number | Animation frame number. |
value | Yes | Gradient Stop[] | Gradient stops at this frame. |
hold | No | Boolean | If true, hold without interpolating. |
Example
{
"id": "background_gradient",
"type": "Gradient",
"value": [
{ "color": [0.0, 0.0, 0.5], "offset": 0 },
{ "color": [0.0, 0.5, 1.0], "offset": 1 }
]
}Image Rule
Replaces an image asset in the animation.
| Field | Type | Description |
value | Image Value | Replacement image details. |
Image Value
| Field | Required | Type | Description |
id | Yes | String | Asset identifier. |
width | Yes | Number | Image width in pixels. |
height | Yes | Number | Image height in pixels. |
url | Yes | String | URL or path to the replacement image. |
Example
{
"id": "logo_image",
"type": "Image",
"value": {
"id": "brand_logo",
"width": 200,
"height": 100,
"url": "i/brand_logo.png"
}
}Text Rule
Overrides text document properties.
| Field | Type | Description |
value | Text object | Replacement text and style properties |
Text rule values can include: text content, font family, font size, fill color, stroke color, styling (bold, italic), and alignment.
Example
{
"id": "headline_text",
"type": "Text",
"value": {
"t": "Hello World",
"s": 48,
"fc": [1, 1, 1]
}
}Expression System
The expression field on any rule enables dynamic values using Lottie expressions. Expressions take precedence over both value and keyframes.
Available globals:
time— Current animation time in secondsvalue— Original property value from the Lottie animationthisComp— Reference to the current compositionthisLayer— Reference to the current layer
All expressions must return a value via $bm_rt:
var $bm_rt;
$bm_rt = calculatedValue;Example: Time-based color animation
{
"id": "background_color",
"type": "Color",
"expression": "var $bm_rt; var t = Math.sin(time * 2); $bm_rt = [0.5 + t * 0.5, 0.3, 0.8];"
}For comprehensive expression documentation, refer to the Lottie Expressions Documentation.
System Behavior
SetThemeactions require the theme to exist in the manifest and be compatible with the current animationDynamic theme loading and theme inheritance are not supported
Theme changes apply to the renderer immediately
Unknown themes are rejected during validation
Named colors (e.g. CSS color names) are not supported in Color rules; use normalized
[R, G, B]arrays