import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; import type { EffectInstance, EffectInstanceType, EffectsState, EffectToolType, } from '../../../shared/types/effects'; import styles from './PxiEffectsOverlay.module.css'; export type PixiEffectsOverlayHandle = { /** Draft-штрих без React re-render родителя; null — сброс. */ setDraft: (instance: EffectInstance | null) => void; }; /** Наборы кадровых VFX — подгружаем только по tool / живым instances. */ type VfxFramePack = | 'fog' | 'fire' | 'rain' | 'water' | 'lightning' | 'sunbeam' | 'poisonCloud'; function mergeDraftState( state: EffectsState | null, draft: EffectInstance | null, ): EffectsState | null { if (!draft) return state; if (!state) { return { revision: 0, serverNowMs: Date.now(), tool: { tool: 'fog', radiusN: 0.05, intensity: 1 }, instances: [draft], }; } const rest = state.instances.filter((i) => i.id !== '__draft__'); return { ...state, instances: [...rest, draft] }; } function vfxPacksForTool(tool: EffectToolType): readonly VfxFramePack[] { switch (tool) { case 'fog': return ['fog']; case 'fire': return ['fire']; case 'rain': return ['rain']; case 'water': return ['water']; case 'lightning': return ['lightning']; case 'sunbeam': return ['sunbeam']; case 'poisonCloud': return ['poisonCloud']; case 'explosion': // Визуал — HTML `