Dynamic Weather Card is a custom weather card for Home Assistant with realistic weather condition animations on Canvas. The project is built using Lit (Web Components) and TypeScript.
Key Features:
- 🎨 Animated weather effects on Canvas
- ☀️ Dynamic background based on time of day (sunrise, day, sunset, night)
- 🌧️ Realistic animations: rain, snow, hail, fog, thunderstorm
- 📊 Hourly and daily forecasts
- 🌍 Automatic language detection from Home Assistant settings
- ⚙️ Full customization of displayed elements
animated-weather-card/
├── src/
│ ├── animations/ # Weather animation modules
│ │ ├── base.ts # Base animation class
│ │ ├── sunny.ts # Sunny weather animation
│ │ ├── rainy.ts # Rain animation
│ │ ├── snowy.ts # Snow animation
│ │ ├── cloudy.ts # Cloudy animation
│ │ ├── foggy.ts # Fog animation
│ │ ├── hail.ts # Hail animation
│ │ └── thunderstorm.ts # Thunderstorm animation
│ ├── components/ # UI components
│ │ ├── card.ts # Main card component
│ │ └── styles.ts # CSS styles
│ ├── icons/ # Weather icons
│ │ ├── weather-conditions.ts
│ │ └── svg-icons.ts
│ ├── internationalization/ # Localization
│ │ ├── locales/ # Translations (en, ru, de, fr, nl, es, it)
│ │ ├── directive.ts
│ │ ├── index.ts
│ │ ├── resolveLanguage.ts
│ │ └── types.ts
│ ├── types/ # TypeScript types
│ │ ├── svg.d.ts
│ │ └── index.ts
│ ├── constants.ts # Constants and mappings
│ ├── utils.ts # Utilities
│ └── index.ts # Entry point
├── build.ts # Build script
├── package.json
└── tsconfig.json
File: src/components/card.ts
The main Web Component built on Lit Element. Responsible for:
- UI Rendering: Displaying weather data, temperature, humidity, wind, etc.
- Canvas Management: Initialization and management of canvas element for animations
- Animation Lifecycle: Starting and stopping the animation loop
- Home Assistant Integration: Fetching weather data from entities via the
hassobject - Interactivity: Handling tap/hold/double-tap user actions
- Responsiveness: ResizeObserver for adapting canvas to container size
Key Methods:
setConfig(config): Set card configurationconnectedCallback(): Initialization when connected to DOMsetupCanvas(): Create and configure canvasdraw(): Main rendering method, selects animation based on weather conditionsgetWeatherData(): Extract weather data from Home AssistantgetTodayForecast()/getWeekForecast(): Get weather forecast
State:
@property hass: Home Assistant object@property config: Card configuration@state currentTime: Current time for clock display
Base Class: src/animations/base.ts
All animations inherit from BaseAnimation, which provides:
- Reference to canvas context (
ctx) - Base methods for drawing clouds (
drawCloud,drawClouds)
Specialized Animations:
SunnyAnimation (sunny.ts)
- Draws sun with rays during daytime
- Draws moon and stars at night
- Adapts to time of day (sunrise, day, sunset, night)
RainyAnimation (rainy.ts)
- Particle system for raindrops
- Support for normal and heavy rain (pouring)
- Dark clouds and drops with gravity effect
SnowyAnimation (snowy.ts)
- Particle system for snowflakes
- Smooth falling with swaying motion
- Various snowflake sizes
CloudyAnimation (cloudy.ts)
- Multiple cloud layers
- Smooth cloud movement
FoggyAnimation (foggy.ts)
- Fog layers with varying opacity
- Fog movement effect
HailAnimation (hail.ts)
- Hail particles with fast falling
- Bounce simulation on ground impact
ThunderstormAnimation (thunderstorm.ts)
- Lightning flashes
- Optional rain
- Dark storm clouds
Usage Pattern:
// In card.ts:428-489
private draw(): void {
const condition = weather.condition.toLowerCase();
switch (condition) {
case 'sunny':
this.animations.sunny?.draw(Date.now(), width, height, timeOfDay);
break;
case 'rainy':
this.animations.rainy?.draw(Date.now(), width, height, timeOfDay, false);
break;
// ...
}
}Structure: src/internationalization/
Components:
index.ts: MainI18nclass for managing translationsdirective.ts: Lit directive for i18n in templatesresolveLanguage.ts: Language detection (auto or from config)locales/: Translations for supported languages
Supported Languages:
- English (en)
- Русский (ru)
- Deutsch (de)
- Français (fr)
- Nederlands (nl)
- Español (es)
- Italiano (it)
Usage:
import { i18n } from '../internationalization';
// In code
i18n.t('feels_like') // "Feels like"
// In templates
html`<div>${i18n.t('weather')}</div>`File: src/utils.ts
Main Functions:
getTimeOfDay(): Determine time of day (sunrise, day, sunset, night)getTimeOfDayWithSunData(sunData): Same but with actual sunrise/sunset datagetBackgroundGradient(timeOfDay): Generate background gradient for time of dayformatForecastTime(datetime): Format time for forecastformatForecastDay(datetime, lang): Format day of weekgetSunriseSunsetData(): Extract sunrise/sunset dataformatTime(date): Format time as HH:MM
File: src/constants.ts
Contains:
DEFAULT_CONFIG: Default configurationTEMPLOW_ATTRIBUTES: List of attributes for finding minimum temperature- Weather condition mappings
File: src/types.ts
TypeScript interfaces and types:
HomeAssistant: Home Assistant object interfaceHassEntity: Home Assistant entityWeatherCardConfig: Card configurationWeatherForecast: Forecast itemTimeOfDay: Time of day with progressBackgroundGradient: Background gradientWeatherEntityAttributes: Weather entity attributes
Using Web Components (Lit Element) for logic and style encapsulation.
ResizeObserverfor tracking container size changes- Reactive properties (
@property,@state) in Lit for automatic UI updates
Different animation classes with unified draw() interface, selected at runtime based on weather conditions.
i18n object for centralized translation management.
BaseAnimation base class defines common methods, overridden in subclasses.
1. setConfig(config)
↓
2. connectedCallback()
↓
3. updateComplete.then()
↓
4. setupCanvas()
↓
5. initializeAnimations()
↓
6. startAnimation() → requestAnimationFrame loop
↓
7. draw() → select and render animation
↓
8. disconnectedCallback() → cleanup resources
Home Assistant Entity
↓
hass.states[config.entity]
↓
getWeatherData() → WeatherData
↓
Render in template
requestAnimationFrame
↓
draw()
↓
Determine condition + timeOfDay
↓
Select animation (sunny/rainy/snowy/etc)
↓
animation.draw(time, width, height, timeOfDay)
↓
Canvas rendering
User config / Home Assistant language
↓
resolveLanguage()
↓
i18n.setLanguage()
↓
Automatic re-render via Lit reactivity
The card is configured via YAML configuration in Home Assistant:
type: custom:dynamic-weather-card
entity: weather.home
name: My Weather
height: 250
language: auto
overlay_opacity: 0.2
wind_speed_unit: ms
show_feels_like: true
show_min_temp: true
show_humidity: true
show_wind: true
show_hourly_forecast: true
hourly_forecast_hours: 5
show_daily_forecast: false
daily_forecast_days: 5
show_sunrise_sunset: true
show_clock: true
clock_position: topOptimizations:
-
Canvas Rendering
- Device Pixel Ratio scaling for clarity on Retina displays
- Canvas context reuse
-
Animation Loop
requestAnimationFramefor smooth 60 FPS animation- Animation loop cleanup on
disconnectedCallback()
-
Event Handling
- Debouncing for resize events via ResizeObserver
- Passive event listeners where possible
-
Memory Management
- Explicit cleanup of timers, intervals, and listeners
- Animation frame cancellation on disconnect
- Create a class in
src/animations/new-animation.ts:
import { BaseAnimation } from './base';
import type { TimeOfDay } from '../types';
export class NewAnimation extends BaseAnimation {
draw(time: number, width: number, height: number, timeOfDay: TimeOfDay): void {
// Your animation logic
}
}- Register in card.ts:211-223:
this.animations = {
// ...
newWeather: new NewAnimation(this.ctx)
};- Add case in card.ts:428-489:
case 'new-condition':
this.animations.newWeather?.draw(Date.now(), width, height, timeOfDay);
break;- Create file
src/internationalization/locales/xx/translation.ts:
export default {
weather: 'Weather',
feels_like: 'Feels like',
// ...
};- Import in src/internationalization/index.ts
Commands:
# Install dependencies
bun install
# Development with hot-reload
bun run dev
# Production build (with linting)
bun run build
# Linting
bun run lint
bun run lint:fix
# Type checking
bun run typecheckBuild Process:
- Entry point: src/index.ts
- Bundler: Bun bundler
- Output file:
dynamic-weather-card.js - Format: ESM (ES Modules)
- Target: Browser
Local testing via demo.html - a static page with various configurations and weather conditions.
- Home Assistant: 2021.4+
- Browsers: Modern browsers with Web Components support
- Weather Integrations: OpenWeatherMap, Met.no, AccuWeather, Yandex Weather, and others
MIT License - open source project.
Document Version: 1.0 Last Updated: 2026-01-20 Project Version: 0.4.0