Воспроизводимость поведения в контексте анимаций означает способность получать идентичный визуальный результат при каждом запуске одного и того же кода. В библиотеке mo.js это особенно важно при использовании случайных значений, stagger-анимаций и генеративных эффектов (частицы, burst-эффекты).
По умолчанию многие параметры в mo.js могут задаваться через строки с диапазонами:
x: { 0: 100 },
radius: { 10: 50 },
duration: '500-1500'
Такие конструкции подразумевают использование встроенного генератора случайных чисел, что приводит к различным результатам при каждом запуске.
Для достижения воспроизводимости требуется:
Самый простой способ добиться повторяемости — отказаться от диапазонов и случайных генераторов:
const circle = new mojs.Shape({
left: 0,
top: 0,
x: 100,
y: 200,
radius: 50,
duration: 1000
});
В этом случае:
Однако такой подход ограничивает выразительность анимаций.
Для более гибкого контроля применяется собственный генератор случайных чисел с фиксированным seed.
function seededRandom(seed) {
let x = Math.sin(seed) * 10000;
return x - Math.floor(x);
}
Использование:
let seed = 42;
function random(min, max) {
const value = seededRandom(seed++);
return min + value * (max - min);
}
Теперь все «случайные» значения будут воспроизводимыми при одинаковом seed:
const circle = new mojs.Shape({
x: random(0, 300),
y: random(0, 300),
radius: random(10, 50),
duration: random(500, 1500)
});
Ключевые свойства:
Stagger (последовательные анимации нескольких элементов) часто используют случайные смещения:
const burst = new mojs.Burst({
count: 10,
delay: 'stagger(100, rand(0, 50))'
});
Такой код не воспроизводим из-за rand().
const delays = Array.from({ length: 10 }, (_, i) => i * 100);
const burst = new mojs.Burst({
count: 10,
children: {
delay: (index) => delays[index]
}
});
Преимущества:
Эффекты Burst и ShapeSwirl активно
используют случайные углы, радиусы и направления.
const burst = new mojs.Burst({
count: 20,
angle: { 0: 360 },
radius: { 50: 150 }
});
Каждый запуск создаёт уникальный рисунок.
const angles = Array.from({ length: 20 }, (_, i) => i * (360 / 20));
const burst = new mojs.Burst({
count: 20,
children: {
angle: (index) => angles[index],
radius: 100
}
});
Особенности:
Даже при фиксированных параметрах возможны расхождения из-за:
const timeline = new mojs.Timeline();
timeline.add(circle1, circle2, burst);
timeline.play();
Преимущества:
Воспроизводимость повышается при явном контроле времени:
circle.tune({ progress: 0.5 });
или:
circle.setProgress(0.5);
Это позволяет:
Повторяющиеся анимации могут вести себя по-разному при случайных параметрах:
repeat: 999,
yoyo: true
Для воспроизводимости:
Для сложных анимаций полезно сохранять конфигурации:
const config = {
x: 100,
y: 200,
radius: 50,
duration: 1000
};
const shape = new mojs.Shape(config);
Преимущества:
Воспроизводимость достигается через сохранение состояния:
const animationState = JSON.stringify(config);
И восстановление:
const restoredConfig = JSON.parse(animationState);
new mojs.Shape(restoredConfig);
Это позволяет:
Методы проверки:
console.log({
x: shape.props.x,
y: shape.props.y
});
Факторы, влияющие на воспроизводимость:
Методы минимизации:
setProgressEasing-функции в mo.js детерминированы, но могут давать различия при:
Рекомендуется:
Порядок инициализации влияет на:
Пример:
const a = createShape();
const b = createShape();
Изменение порядка:
const b = createShape();
const a = createShape();
может изменить результат при использовании общего генератора случайных чисел.
Все параметры описываются заранее:
const scene = {
shapes: [
{ x: 100, y: 100 },
{ x: 200, y: 200 }
]
};
initScene(seed);
rand() без контроляsetProgress для тестовИспользование строковых диапазонов:
duration: '500-1500'
Скрытая случайность в Burst:
angle: { 0: 360 }
Несинхронизированные анимации:
shape1.play();
shape2.play();
Отсутствие контроля seed
Для комплексных анимаций: