Генеративное искусство основано на создании визуальных композиций с использованием алгоритмов, где итоговый результат определяется не вручную, а через правила, случайность и математические зависимости. Библиотека Paper.js предоставляет удобную среду для работы с векторной графикой и идеально подходит для подобных задач благодаря своей объектной модели, системе координат и встроенной поддержке геометрии.
Алгоритмичность Каждый визуальный элемент определяется набором правил: координаты, цвет, форма, поведение во времени.
Случайность (Randomness) Контролируемая случайность позволяет получать уникальные композиции при каждом запуске.
var x = Math.random() * view.size.width;
var y = Math.random() * view.size.height;
Повторяемость (Iteration) Циклы используются для создания множества элементов:
for (var i = 0; i < 100; i++) {
new Path.Circle({
center: Point.random() * view.size,
radius: 10,
fillColor: 'black'
});
}
Правила трансформации Система может изменять элементы по определённым законам: смещение, вращение, масштаб.
Paper.js использует двумерную координатную систему, где начало находится в левом верхнем углу.
Генерация случайных точек:
var point = new Point(
Math.random() * view.size.width,
Math.random() * view.size.height
);
Нормализация координат:
var normalized = point.divide(view.size);
Это позволяет создавать адаптивные композиции, независимые от размера холста.
Использование шума (например, Perlin noise) даёт более естественные формы по сравнению с чистой случайностью.
Простейшая имитация:
function randomOffset(value, range) {
return value + (Math.random() - 0.5) * range;
}
var path = new Path();
path.strokeColor = 'black';
for (var i = 0; i < 10; i++) {
path.add(new Point(i * 50, randomOffset(200, 100)));
}
path.smooth();
Метод smooth() превращает ломаную линию в плавную
кривую, что часто используется в генеративной графике.
var color = new Color(Math.random(), Math.random(), Math.random());
var gradient = new Gradient(['red', 'blue']);
var gradientColor = new GradientColor(gradient, view.bounds.topLeft, view.bounds.bottomRight);
Применение:
var rect = new Path.Rectangle(view.bounds);
rect.fillColor = gradientColor;
Использование HSL позволяет легче контролировать вариации:
var color = new Color({
hue: Math.random() * 360,
saturation: 1,
lightness: 0.5
});
var size = 40;
for (var x = 0; x < view.size.width; x += size) {
for (var y = 0; y < view.size.height; y += size) {
new Path.Circle({
center: [x, y],
radius: Math.random() * 10,
fillColor: 'black'
});
}
}
var center = view.center;
for (var i = 0; i < 360; i += 10) {
var vector = new Point({
length: 100,
angle: i
});
new Path.Line({
from: center,
to: center + vector,
strokeColor: 'black'
});
}
Paper.js поддерживает анимацию через onFrame.
function onFrame(event) {
path.rotate(1);
}
function onFrame(event) {
path.scale(1 + Math.sin(event.time) * 0.01);
}
Группировка позволяет управлять сложными композициями:
var group = new Group();
for (var i = 0; i < 10; i++) {
var circle = new Path.Circle({
center: Point.random() * view.size,
radius: 20,
fillColor: 'black'
});
group.addChild(circle);
}
group.rotate(45);
Простое последовательное построение:
var path = new Path();
path.strokeColor = 'black';
var point = view.center;
for (var i = 0; i < 50; i++) {
point += new Point(Math.random() * 20 - 10, Math.random() * 20 - 10);
path.add(point);
}
Рекурсивное деление:
function divideRect(rect, depth) {
if (depth === 0) return;
var horizontal = Math.random() > 0.5;
if (horizontal) {
var split = rect.height * Math.random();
var top = new Rectangle(rect.topLeft, new Size(rect.width, split));
var bottom = new Rectangle(
rect.topLeft + [0, split],
new Size(rect.width, rect.height - split)
);
divideRect(top, depth - 1);
divideRect(bottom, depth - 1);
} else {
var split = rect.width * Math.random();
var left = new Rectangle(rect.topLeft, new Size(split, rect.height));
var right = new Rectangle(
rect.topLeft + [split, 0],
new Size(rect.width - split, rect.height)
);
divideRect(left, depth - 1);
divideRect(right, depth - 1);
}
new Path.Rectangle({
rectangle: rect,
strokeColor: 'black'
});
}
Генеративные системы могут реагировать на действия:
function onMouseMove(event) {
new Path.Circle({
center: event.point,
radius: Math.random() * 20,
fillColor: 'black'
});
}
var density = 50;
for (var i = 0; i < density; i++) {
// генерация элементов
}
Paper.js предоставляет мощную работу с векторами:
var vector = new Point(100, 0);
vector = vector.rotate(45);
Использование в генерации:
var position = view.center;
var velocity = new Point(2, 3);
function onFrame() {
position += velocity;
}
Минимизация объектов Слишком большое количество Path снижает производительность.
Использование Symbol Повторяющиеся элементы лучше создавать как символы:
var circle = new Path.Circle({
radius: 10,
fillColor: 'black'
});
var symbol = new SymbolDefinition(circle);
for (var i = 0; i < 100; i++) {
symbol.place(Point.random() * view.size);
}
Удаление ненужных объектов
path.remove();
Генеративное искусство часто строится на сочетании подходов:
Пример комбинирования:
for (var i = 0; i < 200; i++) {
var circle = new Path.Circle({
center: Point.random() * view.size,
radius: Math.random() * 30,
fillColor: new Color({
hue: Math.random() * 360,
saturation: 0.7,
lightness: 0.5
})
});
circle.scale(Math.random());
}
1. Инициализация сцены Создание холста и базовых параметров
2. Генерация данных Точки, структуры, параметры
3. Визуализация Создание Path, Group, Symbol
4. Анимация Обновление состояния
5. Взаимодействие Реакция на пользователя
Контролируемый хаос Полностью случайные системы редко дают эстетичный результат. Ограничения делают композицию выразительной.
Повторяемость через seed Использование фиксированного генератора случайных чисел позволяет воспроизводить результат.
Модульность Разделение генерации, логики и визуализации упрощает развитие проекта.
Экспериментирование Небольшие изменения параметров могут радикально изменить результат.
Paper.js предоставляет фундамент для всех этих направлений благодаря удобной работе с геометрией и векторной графикой.