Fireworks animation using Makie¶
Makie is a popular visualisation library in the julia ecosystem. This example will cover topics such as:
- Using colour palettes (colormaps/colorschemes)
- Creating mp4 animations (as an alternative to
@gif
in Plots.jl) - Features of building flow charts (
scatter
):- size
- marker
- colour
- alpha channel
Salute model as a system of differential equations¶
The salute model in this example is described by a system of ordinary differential equations (ODE) that models the motion of particles under the influence of gravity, air resistance and horizontal wind. The system includes four variables: the coordinates $x$ and $y$, and their time derivatives (velocities $v_x$ and $v_y$). The equations are of the form:
- $\frac{dx}{dt} = v_x$
- $\frac{dy}{dt} = v_y$
- $\frac{dv_x}{dt} = -\frac{(k + k_w)}{m} v_x + \frac{k_w}{m} v_w$
- $\frac{dv_y}{dt} = -g - \frac{k}{m} v_y$
Here $g$ is the free fall acceleration, $k$ is the air resistance coefficient, $m$ is the mass of the particle, $v_w$ is the wind speed, $k_w$ is the wind resistance coefficient. This system is solved numerically using the package DifferentialEquations.jl
, which allows to simulate realistic behaviour of salute particles after the explosion.
Installing dependencies and importing libraries¶
To work with animation and solving differential equations we need the packages DifferentialEquations
, CairoMakie
and Random
. Let's install them, if they are not already installed, and import them.
import Pkg; Pkg.add(["DifferentialEquations","CairoMakie","Random"])
using DifferentialEquations
using CairoMakie
using Random
# Устанавливаем seed для воспроизводимости
Random.seed!(1945_2025)
Programme structure¶
Our programme consists of several key components: a set of salutes, each containing particles, for each particle a trajectory is computed, and the trajectory is a set of points $(x, y)$.
Definition of the model and parameters¶
Define the function particle_motion!
, which describes the particle motion according to the above ODE system. We also define the simulation parameters: free fall acceleration, air resistance, particle mass, wind speed and others.
# Функция движения частицы с учетом ветра
function particle_motion!(du, u, p, t)
g, k, m, v_w, k_w = p
du[1] = u[3] # dx/dt = v_x
du[2] = u[4] # dy/dt = v_y
du[3] = -(k + k_w) / m * u[3] + k_w * v_w / m # dv_x/dt = -(k + k_w)/m * v_x + k_w * v_w/m
du[4] = -g - k / m * u[4] # dv_y/dt = -g - k/m * v_y
end
# Параметры
g = 9.81 # ускорение свободного падения
k = 0.1 # коэффициент сопротивления воздуха
m = 0.1 # масса частицы
v_w = 0.1 # скорость горизонтального ветра (м/с, положительная — вправо)
k_w = 0.1 # коэффициент сопротивления ветру
n_fireworks = 3 # количество салютов
n_particles_per_firework = 150 # частиц на салют
v0_values = [1:2.5:25;] # разные начальные скорости
tspan = (0.0, 1.5) # общий временной интервал
saveat = 0.0125 # фиксированный шаг времени
Generating fireworks and selecting colour palettes¶
Each salute is characterised by a random starting position ((x_0, y_0)), an explosion time and a set of three colour palettes. We use Makie.ColorSchemes
to create a visually appealing effect where the particles of each salute are painted in three different colour schemes.
# Список палитр
available_palettes = [
Makie.ColorSchemes.Reds,
Makie.ColorSchemes.pink,
Makie.ColorSchemes.solar,
Makie.ColorSchemes.Blues
]
# Определение салютов
fireworks = []
for i in 1:n_fireworks
# Случайная начальная позиция
x0 = rand(-12:12)
y0 = rand(5:3:15)
# Случайное время взрыва (между 0.0 и 75% tspan)
explosion_time = rand(tspan[1]:0.1:0.75*tspan[2])
# Выбор трёх случайных палитр для салюта
selected_palettes = shuffle(available_palettes)[1:3] # выбираем 3 разные палитры
push!(fireworks, (x0=x0, y0=y0, explosion_time=explosion_time, palettes=selected_palettes))
end
Modelling particle trajectories¶
For each salute, we model the trajectories of its particles by solving the ODE system. Each particle is assigned to one of three selected palettes to create a multi-coloured salute effect.
# Моделирование траекторий для каждого салюта
all_trajectories = []
all_particle_palettes = []
for (idx, fw) in enumerate(fireworks)
trajectories = []
particle_palettes = []
# Разделяем частицы на три группы для трёх палитр
particles_per_palette = div(n_particles_per_firework, 3)
for i in 1:n_particles_per_firework
# Выбор начальной скорости из v0_values
n_v = length(v0_values)
v0 = v0_values[ceil(Int, (i - 1) / (n_particles_per_firework / n_v))%n_v+1] + rand(-2:0.25:2)
θ = 2π * (i - 1) / (n_particles_per_firework / n_v) + rand(-0.1:0.001:0.1) # случайное отклонение угла
u0 = [fw.x0, fw.y0, v0 * cos(θ), v0 * sin(θ)] # начальная позиция и скорость
prob = ODEProblem(particle_motion!, u0, tspan, (g, k, m, v_w, k_w))
sol = solve(prob, Tsit5(), saveat=saveat)
push!(trajectories, [(u[1], u[2]) for u in sol.u])
# Назначаем палитру в зависимости от группы частицы
palette_idx = (i - 1) ÷ particles_per_palette + 1
if palette_idx > 3 # для последнего набора частиц
palette_idx = 3
end
push!(particle_palettes, fw.palettes[palette_idx])
end
push!(all_trajectories, trajectories)
push!(all_particle_palettes, particle_palettes)
end
Creating a scene and adding a starry background¶
Before creating the animation, we set up a scene with a black background and add stars that will be displayed throughout the animation. This creates a night sky effect.
# Визуализация
fig = Figure(backgroundcolor=:black)
ax = Axis(fig[1, 1], aspect=1, limits=(-20, 20, -20, 20),
backgroundcolor=:black, xgridvisible=false, ygridvisible=false,
xticksvisible=false, yticksvisible=false,
xticklabelsvisible=false, yticklabelsvisible=false)
# Добавление звёзд на задний фон
n_stars = 50 # Количество звёзд
x_stars = rand(-20:0.1:20, n_stars) # Случайные x-координаты
y_stars = rand(-20:0.1:20, n_stars) # Случайные y-координаты
Creating an animation¶
We use the record
function from CairoMakie
to create an MP4 animation. In each frame of the animation, redraw the stars and fireworks particles that have already exploded, taking into account the tail effect and individual fading.
# Анимация
total_frames = ceil((tspan[2] - tspan[1]) / saveat) + 1 # общее количество кадров
record(fig, "firework_with_wind.mp4", 1:total_frames-1) do frame_idx
empty!(ax)
# Перерисовываем звёзды
CairoMakie.scatter!(ax, x_stars, y_stars, marker=:star5, color=:yellow, markersize=5, alpha=0.5)
# Текущее время в анимации
current_time = (frame_idx - 1) * saveat
# Проходим по каждому салюту
for firework_idx in 1:n_fireworks
fw = fireworks[firework_idx]
trajectories = all_trajectories[firework_idx]
particle_palettes = all_particle_palettes[firework_idx]
# Проверяем, взорвался ли салют
time_since_explosion = current_time - fw.explosion_time
if time_since_explosion >= 0
# Вычисляем индекс времени относительно времени взрыва
i = Int(round(time_since_explosion / saveat)) + 1
# Ограничиваем i длиной траектории
i = min(i, length(trajectories[1]))
# Индивидуальное выцветание для каждого салюта
if time_since_explosion >= 0
fading_start = 0.6 # 60% от времени видимости
fading_duration = 0.4 # оставшиеся 40% для выцветания
k_fading = time_since_explosion < fading_start ? 1.0 : max(0.0, 1.0 - (time_since_explosion - fading_start) / fading_duration)
# Ограничиваем длину хвоста: отображаем последние 24 позиции
for (traj, palette) in zip(trajectories, particle_palettes)
for j in max(1, i - 24):i
alpha = k_fading * (0.1 + 0.9 * exp(-0.4 * (i - j)))
markersize = 2 + 3 * exp(-0.5 * (i - j))
t = i > 1 ? (j - max(1, i - 14)) / (i - max(1, i - 14)) : 1.0
color = palette[t]
CairoMakie.scatter!(ax, [traj[j]], markersize=markersize, color=color, alpha=alpha)
end
end
end
end
end
end
The animation may take some time to complete, after which a file will be created "firework_with_wind.mp4"
Conclusion¶
In this example, we created a fireworks animation using the Makie
ecosystem with the CairoMakie
backend . We have learned how to model particle motion using differential equations, apply colour palettes for visual effect and create MP4 animations. This approach can be adapted for other visualisation tasks such as modelling planetary motion, simulating explosions or creating artistic animations.