/** * BubbleState — internal physics + render state for a single bubble. * State split enforced: ILayoutEngine writes physics fields, ITweenSystem writes render fields. * Renderer reads ONLY renderX, renderY, renderRadius, renderScale. */ export interface BubbleState { id: string; label: string; value: number; color: string; /** Resolved fill opacity (0–1). 1 = fully opaque. */ opacity: number; icon?: string; x: number; y: number; radius: number; vx: number; vy: number; renderX: number; renderY: number; renderRadius: number; renderScale: number; targetScale: number; tweenProgress: number; tweenFrom?: Readonly<{ x: number; y: number; radius: number; }>; shadowCache?: OffscreenCanvas | HTMLCanvasElement; shadowDirty: boolean; }