packages/engine/src/cutscene/CutsceneRunner.ts — view-агностичный раннер кат-сцен. Сцена — это список шагов; раннер исполняет их последовательно и сообщает active, чтобы игра поставила геймплей на паузу. Никакой привязки к Pixi/вью — только эффекты и камера, передаваемые в шагах.
import { CutsceneRunner, type CutsceneStep } from '@rpg/engine';
const steps: CutsceneStep[] = [
// Произвольный вызов (диалог, тост, логика сцены) + длительность:
{ kind: 'call', fn: () => scene.showToast('Пепел отступил.'), seconds: 1 },
// Плавное перемещение камеры (в мировых юнитах) к точке:
{ kind: 'cameraMove', x: tower.x, y: tower.y, seconds: 1.2, camera: scene.camera },
// Разовый эффект (звук, кольцо резонанса, вспышка частиц):
{ kind: 'burst', fn: () => scene.ringAt(tower), seconds: 1 },
// Поднять флаг прохождения (мгновенно):
{ kind: 'setFlag', flag: 'act1_done', state: game.state },
// Просто пауза:
{ kind: 'wait', seconds: 0.5 },
];
const runner = new CutsceneRunner();
runner.onComplete = () => console.log('сцена закончилась');
runner.play(steps);
seconds и переходит к следующему.seconds: 0 (или undefined у burst/call) не блокирует: следующий стартует в том же тике. Так делают «проверку воздуха» — кольцо и звук в один кадр с продолжением сцены.update проверять runner.active, обновлять раннер и выходить (см. LocationScene.update).sineInOut; точка назначения достигается точно.Конструктор принимает наблюдателя — удобно для отладки:
const runner = new CutsceneRunner((step) => console.log('шаг:', step.kind));
cutscene/__tests__/CutsceneRunner.test.ts — порядок шагов, паузы, интерполяция камеры (точное попадание в точку в конце), флаги, порядок наблюдателя. Конструируется без DOM: new Camera(viewWidth, viewHeight).