How does theming work?

main
eb3546bchore(viewer): virtualized animation list example (#656)
Avatar of Nattu AdnanNattu Adnanposted

How does the themeing works

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

I'll explore the codebase to understand how theming works in the dotlottie-web repository.

Now let me look at the core implementation of theming:

Let me check the core implementation and how it interacts with the theme:

Let me check the core directory structure:

Let me read the dotlottie-player.types.ts to understand the WASM bindings:

Perfect! Now let me check how themes are defined in the manifest and look at some examples:

Now let me check the documentation or README for more context on theming:

Let me check the packages/web README:

Let me look at how themes are accessed and structured in more detail:

Excellent! Now let me create a comprehensive summary. Let me also check the manifest property to understand the structure better:

Perfect! Now I have a comprehensive understanding. Let me create a detailed summary for the user.

##How Theming Works in dotlottie-web

Based on my exploration of the source code, here's how theming works in this library:

###Core Concepts

Theming in dotlottie-web is centered around two main approaches:

  1. Named Themes - Pre-defined themes bundled in the dotLottie file
  2. Theme Data - Custom theme colors provided as JSON at runtime

###Architecture

The theming system is built on several layers:

####1. Manifest-Level Themes

Themes are declared in the .dotlottie file's manifest, which you can access via:

const themes = dotLottie.manifest?.themes ?? [];
// Returns: Array<{ id: string }>

Each animation within a dotLottie can have multiple themes:

const animation = dotLottie.manifest?.animations[0];
const animationThemes = animation?.themes ?? []; // Theme IDs for this animation

####2. Setting Themes

By Theme ID:

// Load a theme from the manifest
const result = dotLottie.setTheme('theme_id');
// Returns: boolean (true if successful)

With Custom Data:

const themeData = {
  c0: {  // Color slot ID
    p: {
      a: 0,
      k: [1, 0, 1],  // RGB color values
    },
  },
};

const result = dotLottie.setTheme(JSON.stringify(themeData));

Reset to Default:

dotLottie.resetTheme();

####3. Configuration

You can set a theme during initialization:

const dotLottie = new DotLottie({
  canvas,
  src: 'animation.lottie',
  themeId: 'initial_theme',
});

Or as a prop in framework wrappers (React, Vue, Solid):

// React
<DotLottie src="animation.lottie" themeId="theme_id" />

// Vue
<DotLottie src="animation.lottie" themeId="theme_id" />

// Solid
<DotLottie src="animation.lottie" themeId={themeId()} />

###Core Implementation Details

The implementation uses:

  • WASM Core: All theme operations are delegated to the WASM module (dotlottie-player.wasm)
  • Render Cycle: When a theme is set, the player automatically:
    1. Calls _dotLottieCore.setTheme(themeId)
    2. Invokes _dotLottieCore.render()
    3. Triggers _draw() to update the canvas
public setTheme(themeId: string): boolean {
  if (this._dotLottieCore === null) return false;

  const themeLoaded = this._dotLottieCore.setTheme(themeId);

  if (themeLoaded) {
    this._dotLottieCore.render();
    this._draw();
  }

  return themeLoaded;
}

###Getting Active Theme

const currentTheme = dotLottie.activeThemeId;

###Theme Transformation (Advanced)

There's a static utility to transform theme data:

DotLottie.transformThemeToLottieSlots(theme: string, slots: string): string

This is a WASM binding that converts theme data to Lottie slot format.

###Practical Example

const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas'),
  src: 'multi_theme_animation.lottie',
});

dotLottie.addEventListener('load', () => {
  // Get available themes
  const themes = dotLottie.manifest?.themes ?? [];
  
  // Show theme selector
  themes.forEach(theme => {
    const option = document.createElement('option');
    option.value = theme.id;
    option.textContent = theme.id;
    themeSelect.appendChild(option);
  });
  
  // Set theme on selection
  themeSelect.addEventListener('change', (e) => {
    if (e.target.value) {
      dotLottie.setTheme(e.target.value);
    } else {
      dotLottie.resetTheme();
    }
  });
});

This is how the demo example works - it dynamically populates a theme selector from the manifest and applies the selected theme when the user changes the selection.

Avatar of Nattu AdnanNattu Adnancommented

Can I dynamically generate themes.

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

Let me search for information about dynamic theme generation in the codebase.

Perfect! Let me search for more examples and understand the theme data structure better:

Let me check if there are any documentation or examples about the theme data structure:

Great! Now I have comprehensive information. Let me provide a detailed answer about dynamic theme generation.

##Yes! You Can Dynamically Generate Themes

Based on the source code and documentation, you absolutely can dynamically generate themes at runtime using the setThemeData() method. This allows you to create custom themes on-the-fly without needing them pre-bundled in the dotLottie file.

###How It Works

The key is using setThemeData() which accepts a JSON object that defines color overrides for animation properties:

const themeData = {
  slot_id_1: {
    p: {
      a: 0,
      k: [r, g, b, a]  // RGB/RGBA values in 0-1 range
    }
  },
  slot_id_2: {
    p: {
      a: 0,
      k: [r, g, b, a]
    }
  }
};

const result = dotLottie.setThemeData(JSON.stringify(themeData));

###Theme Data Structure

The theme data structure follows the Lottie animation format:

  • Slot ID: The identifier of the animated property you want to override (e.g., c0, ball_color, background_color)
  • p object: Contains the property value
    • a: Animation flag (0 = static, 1 = animated)
    • k: The value array
      • For colors: [r, g, b] or [r, g, b, a] where values are 0-1 range (not 0-255)

###Example: Creating a Dynamic Color Theme

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas'),
  src: 'animation.lottie'
});

dotLottie.addEventListener('load', () => {
  // Create a theme dynamically at runtime
  const dynamicTheme = {
    ball_color: {
      p: {
        a: 0,
        k: [0.1, 1, 0.5]  // Light green (RGB normalized 0-1)
      }
    },
    background_color: {
      p: {
        a: 0,
        k: [1, 1, 1]  // White
      }
    }
  };

  // Apply the dynamic theme
  const result = dotLottie.setThemeData(JSON.stringify(dynamicTheme));
  
  if (result) {
    console.log('Theme applied successfully!');
  }
});

###Practical Example: Color Picker

Here's a complete example of dynamically generating themes from user input:

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas'),
  src: 'animation.lottie'
});

// Utility: Convert hex color to 0-1 RGB
function hexToRgb(hex) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? [
    parseInt(result[1], 16) / 255,
    parseInt(result[2], 16) / 255,
    parseInt(result[3], 16) / 255
  ] : [0, 0, 0];
}

// Listen for color changes
document.getElementById('colorPicker').addEventListener('change', (e) => {
  const hex = e.target.value;
  const [r, g, b] = hexToRgb(hex);
  
  // Create and apply dynamic theme
  const themeData = {
    ball_color: {
      p: {
        a: 0,
        k: [r, g, b]
      }
    }
  };
  
  dotLottie.setThemeData(JSON.stringify(themeData));
});

###Important Considerations

  1. Slot IDs Must Exist: You need to know the slot ID of properties you want to theme. These must be defined in the animation's JSON.

  2. Color Range: Colors must be in 0-1 range, not 0-255:

    • RGB(255, 255, 255) → [1, 1, 1]
    • RGB(0, 128, 255) → [0, 0.5, 1]
  3. Animation Flag: The a property indicates if the value is animated:

    • a: 0 = static value
    • a: 1 = animated value
  4. Return Value: Both setTheme() and setThemeData() return a boolean:

    • true = theme applied successfully
    • false = failed (invalid format or slot IDs not found)
  5. Reactive Updates: When applied, the theme automatically:

    • Renders the animation with new values
    • Updates the canvas

###Advanced: Multiple Color Slots

const multiSlotTheme = {
  primary_color: { p: { a: 0, k: [1, 0, 0] } },      // Red
  secondary_color: { p: { a: 0, k: [0, 1, 0] } },    // Green
  accent_color: { p: { a: 0, k: [0, 0, 1] } },       // Blue
  background: { p: { a: 0, k: [0.1, 0.1, 0.1] } }    // Dark gray
};

dotLottie.setThemeData(JSON.stringify(multiSlotTheme));

###Finding Slot IDs in Your Animation

If you're unsure what slot IDs are available:

  1. Open the animation in the Lottie JSON Editor
  2. Search for properties with "sid" (slot ID) fields
  3. The value of "sid" is what you use in your theme data

This makes theming extremely flexible—you can generate themes based on user preferences, time of day, system theme, or any other runtime data!


END OF POST

Log in to add a comment
Claude Haiku 4.5
How does theming work? — LottieFiles/dotlottie-web