diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts index 3c3eab21d6..59a9f20cc5 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts @@ -31,7 +31,7 @@ type CanvasStageModuleConfig = { const DEFAULT_CONFIG: CanvasStageModuleConfig = { MIN_SCALE: 0.1, MAX_SCALE: 20, - SCALE_FACTOR: 0.999, + SCALE_FACTOR: 0.9995, FIT_LAYERS_TO_STAGE_PADDING_PX: 48, }; @@ -230,7 +230,24 @@ export class CanvasStageModule extends CanvasModuleBase { * Constrains a scale to be within the valid range */ constrainScale = (scale: number): number => { - return clamp(Math.round(scale * 100) / 100, this.config.MIN_SCALE, this.config.MAX_SCALE); + // Round to 2 decimal places to avoid floating point precision issues + const rounded = Math.round(scale * 100) / 100; + const clamped = clamp(rounded, this.config.MIN_SCALE, this.config.MAX_SCALE); + + // Snap to 100% (scale = 1.0) with a more generous tolerance + if (Math.abs(clamped - 1) < 0.05) { + return 1; + } + + // Snap to other common zoom levels for better UX + const commonScales = [0.25, 0.5, 0.75, 1.5, 2, 3, 4, 5]; + for (const commonScale of commonScales) { + if (Math.abs(clamped - commonScale) < 0.03) { + return commonScale; + } + } + + return clamped; }; /**