Анимация органических природных явлений — огня, дыма, колыхания воды — традиционно требует применения тяжелой артиллерии: систем частиц, шейдеров WebGL или покадровых спрайтов. Однако когда огонь нужен для компактного микровзаимодействия или пасхалки, такие инструменты избыточно расходуют ресурсы процессора и батареи.
Испанский дизайнер и специалист по креативному кодингу Кармен Ансио (Carmen Ansio) предложила математически изящное решение: реалистичную симуляцию горящей спички на стандартном двухмерном контексте HTML5 Canvas (CanvasRenderingContext2D). Физика мерцания и дыхания пламени занимает пару десятков строк чистого JavaScript без сторонних библиотек и шума Перлина.
Математика мерцания: некратные частоты и неповторяющийся шум
Анимация огня с помощью одной функции Math.sin(t) выглядит механически: человеческий глаз мгновенно считывает равномерное движение маятника.
Секрет живой органики заключается в интерференции нескольких волн с некратными частотами:
- Базовая гармоника
Math.sin(t * 1.7)создает широкое раскачивание языка пламени. - Вторая гармоника с частотой 3.3 и коэффициентом 0.5 добавляет легкий трепет (flutter).
- Третья гармоника с высокой частотой 7.1 и коэффициентом 0.25 вносит быстрое дрожание кончика (jitter).
Сумма трех некратных синусоид образует псевдослучайный шум, повторяющийся лишь раз в 10,5 секунд. Высота пламени пульсирует по независимой синусоиде с периодом 7 секунд. Полный цикл совпадения фаз растягивается на 21 секунду — а поскольку виртуальная спичка сгорает за 13 секунд, зритель видит уникальный рисунок живого огня.
// Генератор процедурного мерцания на базе трех синусоид
function noise(t) {
return (
Math.sin(t * 1.7) +
Math.sin(t * 3.3 + 1.5) * 0.5 +
Math.sin(t * 7.1 + 0.3) * 0.25
);
}
// Отрисовка капли пламени через четыре квадратичные кривые Безье
function drawTeardrop(ctx, sway, h, w, fillStyle) {
ctx.beginPath();
ctx.moveTo(0, 0); // Основание капли у спичечной головки
ctx.quadraticCurveTo(-w, 0, -w, -h * 0.3); // Левая выпуклость
ctx.quadraticCurveTo(-w * 0.55, -h * 0.75, sway, -h); // Подвижная вершина
ctx.quadraticCurveTo(w * 0.55, -h * 0.75, w, -h * 0.3); // Правая выпуклость
ctx.quadraticCurveTo(w, 0, 0, 0); // Возврат в основание
ctx.fillStyle = fillStyle;
ctx.fill();
}
Геометрия капли: кривые Безье и коническое затухание
Форма огня строится замкнутым контуром из четырех квадратичных кривых Безье через метод ctx.quadraticCurveTo(). Основание и боковые опорные точки жестко зафиксированы — колеблется исключительно верхняя вершина капли (sway).
Чтобы пламя казалось объемным, отрисовываются три вложенных слоя с эффектом конического затухания (Tapered Sway):
- Внешняя полупрозрачная оболочка колеблется со 100% расчетной амплитуды.
- Средний желтый ореол отклоняется на 80%.
- Горячее белое ядро пламени отклоняется лишь на 60%.
Разница в отклонении создает эффект вращения пламени вокруг головки спички как вокруг естественного шарнира.
const canvas = document.getElementById('flame-canvas');
const ctx = canvas.getContext('2d');
let lastTime = performance.now();
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
function renderFrame(now) {
const dt = (now - lastTime) / 1000;
lastTime = now;
const t = now / 1000;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const sway = prefersReduced ? 0 : noise(t * 6) * 8;
const height = 70 + (prefersReduced ? 0 : noise(t * 9 + 3) * 16);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2 + 40);
// Послойная отрисовка вложенных капель
drawTeardrop(ctx, sway, height * 1.15, 26, 'rgba(255, 110, 40, 0.55)'); // Оболочка
drawTeardrop(ctx, sway * 0.8, height, 18, 'rgba(255, 175, 60, 0.85)'); // Средний слой
drawTeardrop(ctx, sway * 0.6, height * 0.62, 10, 'rgba(255, 240, 190, 0.95)'); // Ядро
ctx.restore();
requestAnimationFrame(renderFrame);
}
requestAnimationFrame(renderFrame);
Цикл отрисовки: дельта времени, 60 fps и доступность
Код учитывает стандарты производительности. Все расчеты движения масштабируются на дельту времени dt, гарантируя одинаковую скорость анимации на экранах 60 Гц и 120 Гц.
При включенном режиме prefers-reduced-motion анимация отключает колебания и искры, плавно проявляя пламя через прозрачность. Подход Кармен Ансио демонстрирует силу чистого кода: знание базовой тригонометрии способно заменить сотни килобайт внешних графических библиотек.
