Управление с клавиатуры

В Popmotion управление с клавиатуры строится вокруг событийной модели. Клавиатура рассматривается как поток дискретных сигналов, которые преобразуются в значения для анимаций, трансформаций и состояния интерфейса. Базовый инструмент для этого — listen, позволяющий подписываться на DOM-события и преобразовывать их в управляемые потоки.

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

import { listen } from 'popmotion';

listen(document, 'keydown')
  .start((event) => {
    console.log(event.key);
  });

На этом уровне клавиатура уже превращается в поток данных, который можно фильтровать, преобразовывать и связывать с любыми значениями движения.


Фильтрация клавиш и выделение управляющих сигналов

Работа с клавиатурой в интерактивной анимации требует выделения ограниченного набора управляющих клавиш. Чаще всего это стрелки, пробел, Enter и Escape. Фильтрация выполняется на уровне обработчика события.

listen(document, 'keydown')
  .start(({ key }) => {
    if (key === 'ArrowLeft') {
      console.log('влево');
    }
    if (key === 'ArrowRight') {
      console.log('вправо');
    }
  });

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


Преобразование клавиатурных событий в числовые значения

В Popmotion управление движением часто требует перевода дискретных событий в непрерывные значения. Например, стрелки могут изменять координату объекта.

import { listen, value } from 'popmotion';

const x = value(0, (v) => {
  box.style.transform = `translateX(${v}px)`;
});

listen(document, 'keydown')
  .start(({ key }) => {
    if (key === 'ArrowRight') x.set(x.get() + 10);
    if (key === 'ArrowLeft') x.set(x.get() - 10);
  });

Здесь клавиатура управляет состоянием value, а Popmotion отвечает за синхронизацию состояния и визуального представления.


Связь клавиатуры и инерционной анимации

Прямое изменение значения даёт резкий отклик. Для более естественного поведения ввод связывается с физическими моделями, например spring. В этом случае клавиша задаёт цель, а система плавно к ней движется.

import { listen, value, spring } from 'popmotion';

const x = value(0, (v) => {
  box.style.transform = `translateX(${v}px)`;
});

let currentSpring;

const moveTo = (target) => {
  if (currentSpring) currentSpring.stop();

  currentSpring = spring({
    from: x.get(),
    to: target,
    stiffness: 200,
    damping: 20
  }).start(x);
};

listen(document, 'keydown')
  .start(({ key }) => {
    if (key === 'ArrowRight') moveTo(x.get() + 100);
    if (key === 'ArrowLeft') moveTo(x.get() - 100);
  });

Такой подход создаёт ощущение инерции и физической массы объекта, управляемого клавиатурой.


Непрерывное управление через удержание клавиш

Для реализации движения при удержании клавиш используется сочетание keydown и keyup. Состояние нажатия хранится отдельно, а движение обновляется в цикле.

import { listen, value, ticker } from 'popmotion';

const x = value(0, (v) => {
  box.style.transform = `translateX(${v}px)`;
});

let left = false;
let right = false;

listen(document, 'keydown').start(({ key }) => {
  if (key === 'ArrowLeft') left = true;
  if (key === 'ArrowRight') right = true;
});

listen(document, 'keyup').start(({ key }) => {
  if (key === 'ArrowLeft') left = false;
  if (key === 'ArrowRight') right = false;
});

ticker(({ delta }) => {
  if (left) x.update(v => v - delta * 0.5);
  if (right) x.update(v => v + delta * 0.5);
}).start();

Здесь ticker играет роль игрового цикла, синхронизированного с частотой обновления экрана.


Комбинирование клавиатуры и временных анимаций

Клавиатурный ввод может запускать анимации фиксированной длительности через keyframes. Это удобно для переключения состояний интерфейса.

import { listen, keyframes } from 'popmotion';

const fade = keyframes({
  values: [1, 0, 1],
  duration: 600,
  onUpdate: (v) => {
    box.style.opacity = v;
  }
});

listen(document, 'keydown')
  .start(({ key }) => {
    if (key === ' ') fade.start();
  });

Такое управление часто используется для эффектов подтверждения действий или визуальной обратной связи.


Маппинг клавиш в команды управления состоянием

В более сложных интерфейсах клавиатура становится системой команд. Каждая клавиша соответствует действию, которое изменяет глобальное состояние.

const state = {
  mode: 'idle',
  speed: 1
};

listen(document, 'keydown')
  .start(({ key }) => {
    switch (key) {
      case '1':
        state.speed = 1;
        break;
      case '2':
        state.speed = 2;
        break;
      case 'p':
        state.mode = 'pause';
        break;
      case 'r':
        state.mode = 'run';
        break;
    }
  });

Такой подход применяется в интерфейсах, где клавиатура выполняет роль управляющей панели.


Управление направлением движения через векторную модель

Клавиатура может управлять не одной координатой, а вектором движения. Это характерно для игр и визуальных симуляций.

import { listen, value, ticker } from 'popmotion';

const position = value({ x: 0, y: 0 }, (v) => {
  box.style.transform = `translate(${v.x}px, ${v.y}px)`;
});

const velocity = { x: 0, y: 0 };

listen(document, 'keydown').start(({ key }) => {
  if (key === 'ArrowUp') velocity.y = -2;
  if (key === 'ArrowDown') velocity.y = 2;
  if (key === 'ArrowLeft') velocity.x = -2;
  if (key === 'ArrowRight') velocity.x = 2;
});

listen(document, 'keyup').start(({ key }) => {
  if (key.includes('Arrow')) {
    velocity.x = 0;
    velocity.y = 0;
  }
});

ticker(({ delta }) => {
  position.update(v => ({
    x: v.x + velocity.x * delta * 0.1,
    y: v.y + velocity.y * delta * 0.1
  }));
}).start();

Здесь клавиатура задаёт направление, а ticker отвечает за непрерывное движение.


Обработка комбинаций клавиш

Для расширенного управления используется отслеживание нескольких нажатий одновременно. Это позволяет реализовать модификаторы и сложные действия.

const keys = new Set();

listen(document, 'keydown').start(({ key }) => {
  keys.add(key);

  if (keys.has('Shift') && keys.has('ArrowRight')) {
    console.log('ускоренное движение вправо');
  }
});

listen(document, 'keyup').start(({ key }) => {
  keys.delete(key);
});

Комбинации позволяют расширять управляющий интерфейс без увеличения количества отдельных клавиш.


Связывание клавиатуры с жестовыми и pointer-системами

В Popmotion клавиатурный ввод часто объединяется с pointer-событиями, создавая единый механизм управления. Это особенно важно для интерфейсов, где пользователь может переключаться между устройствами ввода без изменения логики.

Клавиатура в таком случае становится альтернативным источником тех же команд, что и pointer или drag.


Управление скоростью анимации через клавиши

Клавиатура может динамически изменять параметры анимации, включая скорость, сопротивление и амплитуду движения.

let speed = 1;

listen(document, 'keydown').start(({ key }) => {
  if (key === '+') speed += 0.2;
  if (key === '-') speed = Math.max(0.2, speed - 0.2);
});

Далее этот параметр применяется в любом вычислении движения или обновления состояния.


Разделение логики ввода и логики анимации

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

Слой ввода:

  • listen(document, 'keydown')
  • обработка клавиш
  • формирование состояния

Слой движения:

  • value
  • spring
  • ticker
  • keyframes

Такое разделение позволяет переиспользовать анимационную логику с разными источниками ввода без изменений.


Дебаунс и защита от повторных срабатываний

При удержании клавиш браузер генерирует повторные keydown события. В системах управления анимацией это может приводить к нежелательным скачкам. Для контроля используется фильтрация по состоянию нажатия.

let pressed = false;

listen(document, 'keydown').start(({ key }) => {
  if (key === ' ' && !pressed) {
    pressed = true;
    console.log('однократное действие');
  }
});

listen(document, 'keyup').start(({ key }) => {
  if (key === ' ') pressed = false;
});

Интеграция клавиатуры в реактивные цепочки Popmotion

Клавиатура становится первым звеном реактивной цепочки, которая может включать трансформации, физику и визуальные обновления. Поток выглядит как последовательность преобразований:

  • событие клавиши
  • нормализация
  • преобразование в команду
  • изменение значения
  • анимация
  • отрисовка

Такая структура позволяет строить предсказуемые системы управления сложной интерактивной графикой и интерфейсами.