feat(effects): вода, облако яда, луч света; пульт и окна демонстрации

- Поле: вода (сплошная заливка по штриху, превью кистью), туман/огонь/дождь без изменений логики.

- Действия: облако яда (частицы, круглая текстура, звук oblako-yada.mp3, длительность как у трека), луч света и заморозка со звуками из public/.

- Пульт: инструменты воды и яда, синхрон SFX, тесты панели и ластика.

- Окно управления: дочернее от окна просмотра (Z-order).

- Типы эффектов, effectsStore prune, hit-test ластика.

Made-with: Cursor
This commit is contained in:
Ivan Fontosh
2026-04-20 11:03:57 +08:00
parent 726c89e104
commit 20c838da7d
19 changed files with 1154 additions and 111 deletions
+53 -3
View File
@@ -1,6 +1,25 @@
export type EffectToolType = 'fog' | 'fire' | 'rain' | 'lightning' | 'freeze' | 'eraser';
export type EffectToolType =
| 'fog'
| 'fire'
| 'rain'
| 'water'
| 'lightning'
| 'sunbeam'
| 'poisonCloud'
| 'freeze'
| 'eraser';
export type EffectInstanceType = 'fog' | 'fire' | 'rain' | 'lightning' | 'freeze' | 'scorch' | 'ice';
export type EffectInstanceType =
| 'fog'
| 'fire'
| 'rain'
| 'water'
| 'lightning'
| 'sunbeam'
| 'poisonCloud'
| 'freeze'
| 'scorch'
| 'ice';
/** Нормализованные координаты (0..1) относительно области предпросмотра/презентации. */
export type NPoint = { x: number; y: number; tMs: number; pressure?: number };
@@ -38,6 +57,14 @@ export type RainInstance = EffectInstanceBase & {
lifetimeMs: number | null;
};
export type WaterInstance = EffectInstanceBase & {
type: 'water';
points: NPoint[];
radiusN: number;
opacity: number;
lifetimeMs: number | null;
};
export type LightningInstance = EffectInstanceBase & {
type: 'lightning';
start: { x: number; y: number };
@@ -47,6 +74,25 @@ export type LightningInstance = EffectInstanceBase & {
lifetimeMs: number;
};
/** Прямой луч сверху к точке удара (как у молнии геометрия штриха, другой визуал). */
export type SunbeamInstance = EffectInstanceBase & {
type: 'sunbeam';
start: { x: number; y: number };
end: { x: number; y: number };
widthN: number;
intensity: number;
lifetimeMs: number;
};
/** «Облако яда» — ядерный гриб в точке удара. */
export type PoisonCloudInstance = EffectInstanceBase & {
type: 'poisonCloud';
at: { x: number; y: number };
radiusN: number;
intensity: number;
lifetimeMs: number;
};
export type FreezeInstance = EffectInstanceBase & {
type: 'freeze';
at: { x: number; y: number };
@@ -69,14 +115,18 @@ export type IceInstance = EffectInstanceBase & {
at: { x: number; y: number };
radiusN: number;
opacity: number;
lifetimeMs: number;
/** `null` — пятно не истекает по времени (снимается только «очистить» или ластик). */
lifetimeMs: number | null;
};
export type EffectInstance =
| FogInstance
| FireInstance
| RainInstance
| WaterInstance
| LightningInstance
| SunbeamInstance
| PoisonCloudInstance
| FreezeInstance
| ScorchInstance
| IceInstance;