import type { LicenseSnapshot } from '../license/licenseSnapshot'; import type { AssetId, EffectsEvent, EffectsState, GraphNodeId, MaterialId, MaterialLegend, MaterialsOverlayEvent, MaterialsOverlayState, MediaAsset, NpcId, NpcRelationId, NpcGroupId, NpcsOverlayEvent, NpcsOverlayState, Project, ProjectId, AppToken, AppPlayer, AppPlayerTeam, PlayerId, PlayerTeamId, PlayerImageOffset, PlayersUpsertProgressEvent, Scene, SceneDarknessEvent, SceneDarknessState, SceneGrid, SceneId, SceneNpcToken, SceneNpcTokensSessionEvent, SceneNpcTokensSessionState, SceneToken, SceneTokensSessionEvent, SceneTokensSessionState, SceneTrap, SceneTrapsEvent, SceneTrapsState, SceneViewEvent, SceneViewState, TokenId, VideoPlaybackEvent, VideoPlaybackState, } from '../types'; import type { NpcImportResolution, SceneImportResolution, StorylineImportMergeReport, StorylineLabels, StorylineListItem, StorylineSelection, } from '../graph/storylineExportImport'; export const ipcChannels = { app: { quit: 'app.quit', getVersion: 'app.getVersion', }, updater: { check: 'updater.check', downloadAndRestart: 'updater.downloadAndRestart', progress: 'updater.progress', }, project: { list: 'project.list', create: 'project.create', open: 'project.open', close: 'project.close', saveNow: 'project.saveNow', get: 'project.get', updateScene: 'project.updateScene', updateConnections: 'project.updateConnections', setCurrentScene: 'project.setCurrentScene', setCurrentGraphNode: 'project.setCurrentGraphNode', importMedia: 'project.importMedia', importCampaignAudio: 'project.importCampaignAudio', updateCampaignAudios: 'project.updateCampaignAudios', upsertMaterial: 'project.upsertMaterial', setMaterialRotation: 'project.setMaterialRotation', setMaterialLegend: 'project.setMaterialLegend', deleteMaterial: 'project.deleteMaterial', setMaterialsOrder: 'project.setMaterialsOrder', pickMaterialImage: 'project.pickMaterialImage', upsertNpc: 'project.upsertNpc', updateNpcFields: 'project.updateNpcFields', updateNpcPosition: 'project.updateNpcPosition', deleteNpc: 'project.deleteNpc', setNpcsOrder: 'project.setNpcsOrder', pickNpcAvatar: 'project.pickNpcAvatar', upsertNpcRelation: 'project.upsertNpcRelation', deleteNpcRelation: 'project.deleteNpcRelation', upsertNpcGroup: 'project.upsertNpcGroup', deleteNpcGroup: 'project.deleteNpcGroup', setNpcGroupsOrder: 'project.setNpcGroupsOrder', importScenePreview: 'project.importScenePreview', clearScenePreview: 'project.clearScenePreview', assetFileUrl: 'project.assetFileUrl', updateSceneGraphNodePosition: 'project.updateSceneGraphNodePosition', addSceneGraphNode: 'project.addSceneGraphNode', removeSceneGraphNode: 'project.removeSceneGraphNode', addSceneGraphEdge: 'project.addSceneGraphEdge', removeSceneGraphEdge: 'project.removeSceneGraphEdge', setSceneGraphNodeStart: 'project.setSceneGraphNodeStart', setSceneGraphNodeSideStoryStart: 'project.setSceneGraphNodeSideStoryStart', updateSideStoryLineTitle: 'project.updateSideStoryLineTitle', deleteScene: 'project.deleteScene', setSceneListOrder: 'project.setSceneListOrder', rename: 'project.rename', importZip: 'project.importZip', exportZip: 'project.exportZip', getProjectStorylines: 'project.getProjectStorylines', peekImportZip: 'project.peekImportZip', pickImportZipFile: 'project.pickImportZipFile', peekImportZipPath: 'project.peekImportZipPath', peekImportFromProject: 'project.peekImportFromProject', mergeImportZip: 'project.mergeImportZip', mergeImportFromProject: 'project.mergeImportFromProject', importZipFromPath: 'project.importZipFromPath', importFoundry: 'project.importFoundry', pickFoundrySource: 'project.pickFoundrySource', deleteProject: 'project.deleteProject', importZipProgress: 'project.importZipProgress', exportZipProgress: 'project.exportZipProgress', scenePreviewImportProgress: 'project.scenePreviewImportProgress', materialUpsertProgress: 'project.materialUpsertProgress', npcUpsertProgress: 'project.npcUpsertProgress', }, windows: { openMultiWindow: 'windows.openMultiWindow', closeMultiWindow: 'windows.closeMultiWindow', togglePresentationFullscreen: 'windows.togglePresentationFullscreen', getMultiWindowState: 'windows.getMultiWindowState', multiWindowStateChanged: 'windows.multiWindowStateChanged', openSceneDescription: 'windows.openSceneDescription', closeSceneDescription: 'windows.closeSceneDescription', getSceneDescriptionContent: 'windows.getSceneDescriptionContent', sceneDescriptionContent: 'windows.sceneDescriptionContent', openMaterials: 'windows.openMaterials', closeMaterials: 'windows.closeMaterials', openNpcsEditor: 'windows.openNpcsEditor', closeNpcsEditor: 'windows.closeNpcsEditor', openNpcs: 'windows.openNpcs', closeNpcs: 'windows.closeNpcs', openSceneEditor: 'windows.openSceneEditor', closeSceneEditor: 'windows.closeSceneEditor', }, session: { stateChanged: 'session.stateChanged', }, effects: { getState: 'effects.getState', dispatch: 'effects.dispatch', stateChanged: 'effects.stateChanged', }, materialsOverlay: { getState: 'materialsOverlay.getState', dispatch: 'materialsOverlay.dispatch', stateChanged: 'materialsOverlay.stateChanged', }, npcsOverlay: { getState: 'npcsOverlay.getState', dispatch: 'npcsOverlay.dispatch', stateChanged: 'npcsOverlay.stateChanged', }, sceneDarkness: { getState: 'sceneDarkness.getState', dispatch: 'sceneDarkness.dispatch', stateChanged: 'sceneDarkness.stateChanged', }, sceneTraps: { getState: 'sceneTraps.getState', dispatch: 'sceneTraps.dispatch', stateChanged: 'sceneTraps.stateChanged', }, sceneView: { getState: 'sceneView.getState', dispatch: 'sceneView.dispatch', stateChanged: 'sceneView.stateChanged', }, tokens: { list: 'tokens.list', upsert: 'tokens.upsert', delete: 'tokens.delete', pickImage: 'tokens.pickImage', imageUrl: 'tokens.imageUrl', stateChanged: 'tokens.stateChanged', }, sceneTokensSession: { getState: 'sceneTokensSession.getState', dispatch: 'sceneTokensSession.dispatch', stateChanged: 'sceneTokensSession.stateChanged', }, players: { list: 'players.list', upsert: 'players.upsert', delete: 'players.delete', setOrder: 'players.setOrder', upsertTeam: 'players.upsertTeam', deleteTeam: 'players.deleteTeam', setTeamsOrder: 'players.setTeamsOrder', assignTeam: 'players.assignTeam', pickImage: 'players.pickImage', imageUrl: 'players.imageUrl', upsertProgress: 'players.upsertProgress', stateChanged: 'players.stateChanged', }, sceneNpcTokensSession: { getState: 'sceneNpcTokensSession.getState', dispatch: 'sceneNpcTokensSession.dispatch', stateChanged: 'sceneNpcTokensSession.stateChanged', }, video: { getState: 'video.getState', dispatch: 'video.dispatch', stateChanged: 'video.stateChanged', }, license: { getStatus: 'license.getStatus', setToken: 'license.setToken', clearToken: 'license.clearToken', acceptEula: 'license.acceptEula', statusChanged: 'license.statusChanged', }, } as const; export type ZipProgressEvent = { kind: 'import' | 'export'; stage: 'copy' | 'unzip' | 'zip' | 'done'; percent: number; // 0..100 detail?: string; }; export type ScenePreviewImportEvent = { sceneId: SceneId; assetId: AssetId; phase: 'queued' | 'optimizing' | 'thumbnail' | 'done' | 'error'; project?: Project; message?: string; }; export type MaterialUpsertProgressEvent = { percent: number; stage: string; detail?: string; }; export type NpcUpsertProgressEvent = MaterialUpsertProgressEvent; export type UpdaterCheckResponse = | { outcome: 'not_packaged' } | { outcome: 'no_license' } | { outcome: 'current'; currentVersion: string } | { outcome: 'available'; version: string } | { outcome: 'error'; message: string }; export type UpdaterDownloadResponse = { ok: true } | { ok: false; message: string }; export type UpdaterProgressPhase = | 'checking' | 'available' | 'not-available' | 'downloading' | 'installing' | 'error'; export type UpdaterProgressEvent = { phase: UpdaterProgressPhase; /** 0..100 при phase=downloading */ percent?: number; version?: string; message?: string; }; export type IpcEventMap = { [ipcChannels.session.stateChanged]: { state: SessionState }; [ipcChannels.effects.stateChanged]: { state: EffectsState }; [ipcChannels.materialsOverlay.stateChanged]: { state: MaterialsOverlayState }; [ipcChannels.npcsOverlay.stateChanged]: { state: NpcsOverlayState }; [ipcChannels.sceneDarkness.stateChanged]: { state: SceneDarknessState }; [ipcChannels.sceneTraps.stateChanged]: { state: SceneTrapsState }; [ipcChannels.sceneView.stateChanged]: { state: SceneViewState }; [ipcChannels.tokens.stateChanged]: { tokens: AppToken[] }; [ipcChannels.sceneTokensSession.stateChanged]: { state: SceneTokensSessionState }; [ipcChannels.players.stateChanged]: { players: AppPlayer[]; teams: AppPlayerTeam[] }; [ipcChannels.players.upsertProgress]: PlayersUpsertProgressEvent; [ipcChannels.sceneNpcTokensSession.stateChanged]: { state: SceneNpcTokensSessionState }; [ipcChannels.video.stateChanged]: { state: VideoPlaybackState }; [ipcChannels.license.statusChanged]: { snapshot: LicenseSnapshot }; [ipcChannels.windows.multiWindowStateChanged]: { open: boolean }; [ipcChannels.windows.sceneDescriptionContent]: { html: string }; [ipcChannels.project.importZipProgress]: ZipProgressEvent; [ipcChannels.project.exportZipProgress]: ZipProgressEvent; [ipcChannels.project.scenePreviewImportProgress]: ScenePreviewImportEvent; [ipcChannels.project.materialUpsertProgress]: MaterialUpsertProgressEvent; [ipcChannels.project.npcUpsertProgress]: NpcUpsertProgressEvent; [ipcChannels.updater.progress]: UpdaterProgressEvent; }; export type IpcInvokeMap = { [ipcChannels.app.quit]: { req: Record; res: { ok: true }; }; [ipcChannels.app.getVersion]: { req: Record; res: { version: string; buildNumber: string | null; packaged: boolean }; }; [ipcChannels.updater.check]: { req: Record; res: UpdaterCheckResponse; }; [ipcChannels.updater.downloadAndRestart]: { req: { version: string }; res: UpdaterDownloadResponse; }; [ipcChannels.project.list]: { req: Record; res: { projects: { id: ProjectId; name: string; updatedAt: string; fileName: string }[] }; }; [ipcChannels.project.create]: { req: { name: string }; res: { project: Project }; }; [ipcChannels.project.open]: { req: { projectId: ProjectId }; res: { project: Project }; }; [ipcChannels.project.close]: { req: Record; res: { ok: true }; }; [ipcChannels.project.get]: { req: Record; res: { project: Project | null }; }; [ipcChannels.project.saveNow]: { req: Record; res: { ok: true }; }; [ipcChannels.project.updateScene]: { req: { sceneId: SceneId; patch: ScenePatch }; res: { scene: Scene }; }; [ipcChannels.project.updateConnections]: { req: { sceneId: SceneId; connections: SceneId[] }; res: { scene: Scene }; }; [ipcChannels.project.setCurrentScene]: { req: { sceneId: SceneId | null }; res: { currentSceneId: SceneId | null }; }; [ipcChannels.project.setCurrentGraphNode]: { req: { graphNodeId: GraphNodeId | null }; res: { currentGraphNodeId: GraphNodeId | null; currentSceneId: SceneId | null }; }; [ipcChannels.project.importMedia]: { req: { sceneId: SceneId; filePaths?: string[] }; res: { project: Project; imported: MediaAsset[] }; }; [ipcChannels.project.importCampaignAudio]: { req: { filePaths?: string[] }; res: { canceled: boolean; project: Project; imported: MediaAsset[] }; }; [ipcChannels.project.updateCampaignAudios]: { req: { audios: Project['campaignAudios'] }; res: { project: Project }; }; [ipcChannels.project.upsertMaterial]: { req: { materialId?: MaterialId; name: string; filePath?: string }; res: { project: Project }; }; [ipcChannels.project.setMaterialRotation]: { req: { materialId: MaterialId; rotationDeg: 0 | 90 | 180 | 270 }; res: { project: Project }; }; [ipcChannels.project.setMaterialLegend]: { req: { materialId: MaterialId; legend: MaterialLegend | null }; res: { project: Project }; }; [ipcChannels.project.deleteMaterial]: { req: { materialId: MaterialId }; res: { project: Project }; }; [ipcChannels.project.setMaterialsOrder]: { req: { materialIds: MaterialId[] }; res: { project: Project }; }; [ipcChannels.project.pickMaterialImage]: { req: Record; res: | { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.project.upsertNpc]: { req: { npcId?: NpcId; name: string; description?: string; filePath?: string; groupId?: NpcGroupId | null; ringColor?: string; imageOffset?: PlayerImageOffset; imageScale?: number; }; res: { project: Project }; }; [ipcChannels.project.updateNpcFields]: { req: { npcId: NpcId; name?: string; description?: string; groupId?: NpcGroupId | null; ringColor?: string; imageOffset?: PlayerImageOffset; imageScale?: number; }; res: { project: Project }; }; [ipcChannels.project.updateNpcPosition]: { req: { npcId: NpcId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.deleteNpc]: { req: { npcId: NpcId }; res: { project: Project }; }; [ipcChannels.project.setNpcsOrder]: { req: { npcIds: NpcId[] }; res: { project: Project }; }; [ipcChannels.project.pickNpcAvatar]: { req: Record; res: | { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.project.upsertNpcRelation]: { req: { relationId?: NpcRelationId; sourceNpcId: NpcId; targetNpcId: NpcId; label: string; }; res: { project: Project }; }; [ipcChannels.project.deleteNpcRelation]: { req: { relationId: NpcRelationId }; res: { project: Project }; }; [ipcChannels.project.upsertNpcGroup]: { req: { groupId?: NpcGroupId; name: string; color?: string; parentId?: NpcGroupId | null; }; res: { project: Project }; }; [ipcChannels.project.deleteNpcGroup]: { req: { groupId: NpcGroupId }; res: { project: Project }; }; [ipcChannels.project.setNpcGroupsOrder]: { req: { groupIds: NpcGroupId[] }; res: { project: Project }; }; [ipcChannels.project.importScenePreview]: { req: { sceneId: SceneId; filePath?: string }; res: { project: Project; assetId: AssetId | null; background: boolean }; }; [ipcChannels.project.clearScenePreview]: { req: { sceneId: SceneId }; res: { project: Project }; }; [ipcChannels.project.assetFileUrl]: { req: { assetId: AssetId }; res: { url: string | null }; }; [ipcChannels.project.updateSceneGraphNodePosition]: { req: { nodeId: GraphNodeId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.addSceneGraphNode]: { req: { sceneId: SceneId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.removeSceneGraphNode]: { req: { nodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.addSceneGraphEdge]: { req: { sourceGraphNodeId: GraphNodeId; targetGraphNodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.removeSceneGraphEdge]: { req: { edgeId: string }; res: { project: Project }; }; [ipcChannels.project.setSceneGraphNodeStart]: { req: { graphNodeId: GraphNodeId | null }; res: { project: Project }; }; [ipcChannels.project.setSceneGraphNodeSideStoryStart]: { req: { graphNodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.updateSideStoryLineTitle]: { req: { graphNodeId: GraphNodeId; title: string }; res: { project: Project }; }; [ipcChannels.project.deleteScene]: { req: { sceneId: SceneId }; res: { project: Project }; }; [ipcChannels.project.setSceneListOrder]: { req: { sceneListOrder: SceneId[] }; res: { project: Project }; }; [ipcChannels.project.rename]: { req: { name: string; fileBaseName: string }; res: { project: Project }; }; [ipcChannels.project.importZip]: { req: Record; res: { canceled: true } | { canceled: false; project: Project }; }; [ipcChannels.project.getProjectStorylines]: { req: { projectId: ProjectId; labels: StorylineLabels }; res: { storylines: StorylineListItem[]; npcs: { id: string; name: string }[]; }; }; [ipcChannels.project.peekImportZip]: { req: { labels: StorylineLabels; targetHasMainStart: boolean }; res: | { canceled: true } | { canceled: false; filePath: string; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.pickImportZipFile]: { req: Record; res: { canceled: true } | { canceled: false; filePath: string }; }; [ipcChannels.project.peekImportZipPath]: { req: { filePath: string; labels: StorylineLabels; targetHasMainStart: boolean }; res: { filePath: string; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.peekImportFromProject]: { req: { sourceProjectId: ProjectId; labels: StorylineLabels; targetHasMainStart: boolean }; res: { sourceProjectId: ProjectId; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.mergeImportZip]: { req: { filePath: string; storylineSelections: StorylineSelection[]; sceneResolutions: SceneImportResolution[]; npcResolutions?: NpcImportResolution[]; }; res: { project: Project; report: StorylineImportMergeReport }; }; [ipcChannels.project.mergeImportFromProject]: { req: { sourceProjectId: ProjectId; storylineSelections: StorylineSelection[]; sceneResolutions: SceneImportResolution[]; npcResolutions?: NpcImportResolution[]; }; res: { project: Project; report: StorylineImportMergeReport }; }; [ipcChannels.project.importZipFromPath]: { req: { filePath: string }; res: { project: Project }; }; [ipcChannels.project.pickFoundrySource]: { req: { mode: 'folder' | 'archive' }; res: { canceled: true } | { canceled: false; sourcePath: string }; }; [ipcChannels.project.importFoundry]: { req: { sourcePath: string }; res: { project: Project }; }; [ipcChannels.project.exportZip]: { req: { projectId: ProjectId; storylineSelections: StorylineSelection[]; npcIds: string[]; labels: StorylineLabels; }; res: { canceled: true } | { canceled: false }; }; [ipcChannels.project.deleteProject]: { req: { projectId: ProjectId }; res: { ok: true }; }; [ipcChannels.windows.openMultiWindow]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeMultiWindow]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.togglePresentationFullscreen]: { req: Record; res: { ok: true; isFullScreen: boolean }; }; [ipcChannels.windows.getMultiWindowState]: { req: Record; res: { open: boolean }; }; [ipcChannels.windows.openSceneDescription]: { req: { html: string }; res: { ok: true }; }; [ipcChannels.windows.closeSceneDescription]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.getSceneDescriptionContent]: { req: Record; res: { html: string }; }; [ipcChannels.windows.openMaterials]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeMaterials]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.openNpcsEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeNpcsEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.openNpcs]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeNpcs]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.openSceneEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeSceneEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.materialsOverlay.getState]: { req: Record; res: { state: MaterialsOverlayState }; }; [ipcChannels.materialsOverlay.dispatch]: { req: { event: MaterialsOverlayEvent }; res: { ok: true }; }; [ipcChannels.npcsOverlay.getState]: { req: Record; res: { state: NpcsOverlayState }; }; [ipcChannels.npcsOverlay.dispatch]: { req: { event: NpcsOverlayEvent }; res: { ok: true }; }; [ipcChannels.effects.getState]: { req: Record; res: { state: EffectsState }; }; [ipcChannels.effects.dispatch]: { req: { event: EffectsEvent }; res: { ok: true }; }; [ipcChannels.sceneDarkness.getState]: { req: Record; res: { state: SceneDarknessState }; }; [ipcChannels.sceneDarkness.dispatch]: { req: { event: SceneDarknessEvent }; res: { ok: true }; }; [ipcChannels.sceneTraps.getState]: { req: Record; res: { state: SceneTrapsState }; }; [ipcChannels.sceneTraps.dispatch]: { req: { event: SceneTrapsEvent }; res: { ok: true }; }; [ipcChannels.sceneView.getState]: { req: Record; res: { state: SceneViewState }; }; [ipcChannels.sceneView.dispatch]: { req: { event: SceneViewEvent }; res: { ok: true }; }; [ipcChannels.tokens.list]: { req: Record; res: { tokens: AppToken[] }; }; [ipcChannels.tokens.upsert]: { req: { id?: TokenId | null; name: string; filePath?: string | null }; res: { token: AppToken }; }; [ipcChannels.tokens.delete]: { req: { id: TokenId }; res: { ok: true }; }; [ipcChannels.tokens.pickImage]: { req: Record; res: { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.tokens.imageUrl]: { req: { id: TokenId }; res: { url: string | null }; }; [ipcChannels.sceneTokensSession.getState]: { req: Record; res: { state: SceneTokensSessionState }; }; [ipcChannels.sceneTokensSession.dispatch]: { req: { event: SceneTokensSessionEvent }; res: { ok: true }; }; [ipcChannels.players.list]: { req: Record; res: { players: AppPlayer[]; teams: AppPlayerTeam[] }; }; [ipcChannels.players.upsert]: { req: { id?: PlayerId | null; name: string; filePath?: string | null; teamId?: PlayerTeamId | null; ringColor?: string; imageOffset?: PlayerImageOffset; imageScale?: number; }; res: { player: AppPlayer }; }; [ipcChannels.players.delete]: { req: { id: PlayerId }; res: { ok: true }; }; [ipcChannels.players.setOrder]: { req: { playerIds: PlayerId[] }; res: { players: AppPlayer[] }; }; [ipcChannels.players.upsertTeam]: { req: { id?: PlayerTeamId | null; name: string; color?: string }; res: { team: AppPlayerTeam }; }; [ipcChannels.players.deleteTeam]: { req: { id: PlayerTeamId }; res: { ok: true }; }; [ipcChannels.players.setTeamsOrder]: { req: { teamIds: PlayerTeamId[] }; res: { teams: AppPlayerTeam[] }; }; [ipcChannels.players.assignTeam]: { req: { playerId: PlayerId; teamId: PlayerTeamId | null }; res: { player: AppPlayer | null }; }; [ipcChannels.players.pickImage]: { req: Record; res: { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.players.imageUrl]: { req: { id: PlayerId }; res: { url: string | null }; }; [ipcChannels.sceneNpcTokensSession.getState]: { req: Record; res: { state: SceneNpcTokensSessionState }; }; [ipcChannels.sceneNpcTokensSession.dispatch]: { req: { event: SceneNpcTokensSessionEvent }; res: { ok: true }; }; [ipcChannels.video.getState]: { req: Record; res: { state: VideoPlaybackState }; }; [ipcChannels.video.dispatch]: { req: { event: VideoPlaybackEvent }; res: { ok: true }; }; [ipcChannels.license.getStatus]: { req: Record; res: LicenseSnapshot; }; [ipcChannels.license.setToken]: { req: { token: string }; res: LicenseSnapshot; }; [ipcChannels.license.clearToken]: { req: Record; res: LicenseSnapshot; }; [ipcChannels.license.acceptEula]: { req: { version: number }; res: { ok: true }; }; }; export type SessionState = { project: Project | null; currentSceneId: SceneId | null; }; export type LegacyIpcEventMap = { [ipcChannels.session.stateChanged]: { state: SessionState }; [ipcChannels.effects.stateChanged]: { state: EffectsState }; [ipcChannels.materialsOverlay.stateChanged]: { state: MaterialsOverlayState }; [ipcChannels.npcsOverlay.stateChanged]: { state: NpcsOverlayState }; [ipcChannels.sceneDarkness.stateChanged]: { state: SceneDarknessState }; [ipcChannels.sceneTraps.stateChanged]: { state: SceneTrapsState }; [ipcChannels.sceneView.stateChanged]: { state: SceneViewState }; [ipcChannels.tokens.stateChanged]: { tokens: AppToken[] }; [ipcChannels.sceneTokensSession.stateChanged]: { state: SceneTokensSessionState }; [ipcChannels.players.stateChanged]: { players: AppPlayer[]; teams: AppPlayerTeam[] }; [ipcChannels.players.upsertProgress]: PlayersUpsertProgressEvent; [ipcChannels.sceneNpcTokensSession.stateChanged]: { state: SceneNpcTokensSessionState }; [ipcChannels.video.stateChanged]: { state: VideoPlaybackState }; [ipcChannels.license.statusChanged]: Record; }; export type ScenePatch = { title?: string; description?: string; previewAssetId?: AssetId | null; previewAssetType?: 'image' | 'video' | null; previewThumbAssetId?: AssetId | null; previewVideoAutostart?: boolean; previewRotationDeg?: 0 | 90 | 180 | 270; darkenScene?: boolean; traps?: SceneTrap[]; tokens?: SceneToken[]; npcTokens?: SceneNpcToken[]; grid?: SceneGrid; settings?: Partial; media?: Partial; layout?: Partial; };