Rand - случайное распределение

Механизм случайных значений в библиотеке mo.js реализован через специальный инструмент Rand, который позволяет задавать диапазоны, распределения и динамически изменяющиеся параметры анимации. Это ключевой элемент при создании «живых», органичных эффектов, где отсутствует строгая повторяемость.

В отличие от статических значений, Rand обеспечивает вариативность: каждое воспроизведение анимации может выглядеть немного иначе, что особенно важно для эффектов частиц, всплесков, взрывов и природных движений.


Базовый синтаксис Rand

В mo.js случайные значения задаются строкой с использованием конструкции:

'rand(min, max)'

Пример:

radius: 'rand(10, 50)'

Это означает, что при каждом запуске анимации радиус будет случайным числом в диапазоне от 10 до 50.


Принцип работы

  • Значение вычисляется один раз при создании анимации (если не указано иное)
  • Для каждого экземпляра анимации значение может отличаться
  • Используется равномерное распределение

Использование в различных свойствах

Rand можно применять практически к любым числовым параметрам:

Геометрия

x: 'rand(-100, 100)',
y: 'rand(-50, 50)',
radius: 'rand(20, 80)'

Цвета (частично)

fill: ['red', 'rand(blue, green)'] // чаще комбинируется с массивами

Вращение

angle: 'rand(0, 360)'

Продолжительность

duration: 'rand(300, 1000)'

Вложенные случайные значения

mo.js поддерживает комбинирование случайностей:

radius: {
  0: 'rand(10, 20)',
  100: 'rand(50, 100)'
}

В этом случае:

  • начальное значение радиуса — случайное число от 10 до 20
  • конечное — от 50 до 100

Каждый элемент анимации получает собственную траекторию.


Rand в массивах значений

Часто используется совместно с массивами для создания сложных вариаций:

scale: [1, 'rand(1.5, 3)']

или

fill: ['#ff0000', '#00ff00', '#0000ff']
radius: ['rand(10, 20)', 'rand(30, 60)']

Динамическая случайность через stagger

При работе с stagger (например, в mojs.Burst) Rand усиливает эффект распределения:

children: {
  radius: 'rand(5, 20)',
  delay: 'stagger(0, rand(10, 50))'
}

Каждый элемент:

  • получает случайный радиус
  • появляется с разной задержкой

Повторная генерация значений

По умолчанию Rand вычисляется один раз. Чтобы добиться изменения значений при каждом запуске:

Использование repeat

repeat: 3,
radius: 'rand(10, 50)'

Однако значение всё равно фиксируется на цикл.

Пересоздание анимации

На практике для полной случайности создаётся новый экземпляр:

const createAnimation = () => new mojs.Shape({
  radius: 'rand(10, 50)'
});

Использование функции вместо строки

Для более сложной логики допускается использование функций:

radius: () => Math.random() * 40 + 10

Преимущества:

  • полный контроль над распределением
  • возможность использовать нелинейные зависимости

Нелинейные распределения

Стандартный rand(min, max) использует равномерное распределение. Для более реалистичных эффектов:

Квадратичное распределение

radius: () => Math.pow(Math.random(), 2) * 50

Смещение к минимуму

radius: () => Math.random() * Math.random() * 50

Смещение к максимуму

radius: () => 50 - Math.random() * Math.random() * 50

Практика: генерация частиц

new mojs.Burst({
  count: 10,
  children: {
    radius: 'rand(5, 15)',
    angle: 'rand(0, 360)',
    duration: 'rand(300, 800)',
    delay: 'rand(0, 200)'
  }
});

Результат:

  • каждая частица уникальна
  • создаётся ощущение естественного разброса

Rand и производительность

Использование случайных значений:

  • практически не влияет на производительность при небольшом количестве элементов
  • может стать затратным при массовой генерации (сотни элементов)

Рекомендации:

  • избегать сложных функций внутри Rand
  • минимизировать пересоздание анимаций
  • использовать кэширование, если значения не критичны

Ограничения

  • Работает только с числовыми значениями
  • Не поддерживает сложные типы (объекты, массивы напрямую)
  • Не управляет распределением (только равномерное)

Расширенные паттерны использования

Комбинирование с easing

radius: {
  0: 'rand(10, 20)',
  100: 'rand(50, 100)',
  easing: 'quad.out'
}

Случайные траектории

x: [0, 'rand(-200, 200)'],
y: [0, 'rand(-200, 200)']

Имитация шума

x: () => (Math.random() - 0.5) * 100

Сравнение с Math.random()

Подход Преимущества Недостатки
rand() Простота, встроенность Ограниченная гибкость
Math.random() Полный контроль Более многословный код

Архитектурная роль Rand

Rand выполняет роль:

  • генератора вариативности
  • средства борьбы с «механичностью» анимаций
  • инструмента композиции сложных визуальных эффектов

Без него большинство эффектов выглядели бы повторяющимися и искусственными.


Типичные сценарии применения

  • системы частиц
  • взрывы и всплески
  • генерация случайных траекторий
  • имитация природных движений (дым, огонь, дождь)
  • декоративные UI-анимации

Ошибки и антипаттерны

Чрезмерная случайность

x: 'rand(-1000, 1000)'

Приводит к хаотичности и потере визуального контроля.

Отсутствие ограничений

Слишком широкий диапазон делает анимацию нечитабельной.

Игнорирование композиции

Случайность должна быть подчинена общей логике движения.


Контроль случайности

Для более управляемых эффектов:

  • сужение диапазона
  • использование нескольких уровней Rand
  • комбинирование с фиксированными значениями

Пример:

radius: ['rand(10, 20)', 'rand(30, 40)']

Связка с timeline

Rand особенно эффективен в цепочках анимаций:

const timeline = new mojs.Timeline();

for (let i = 0; i < 5; i++) {
  timeline.add(new mojs.Shape({
    x: 'rand(-100, 100)',
    delay: i * 100
  }));
}

Создаётся ощущение естественного распределения событий.


Итоговая роль в системе mo.js

Rand — это не просто генератор случайных чисел, а инструмент формирования визуального разнообразия. Его грамотное использование позволяет создавать анимации, приближенные к естественным процессам, избегая повторяемости и шаблонности.