Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: edge anchor clamping, transition NaN guard, PPTX aspect ratio

- Diagrams: nearestEdgeAnchor clamps to actual point coordinates, not center (#562)
- Slides: createTransition guards against NaN/Infinity duration (#560)
- Slides: PPTX normalizePosition uses uniform scaling to preserve aspect ratio (#563)

+14 -11
+4 -4
src/diagrams/whiteboard-geometry.ts
··· 164 164 const aspectThreshold = Math.atan2(shape.height / 2, shape.width / 2); 165 165 166 166 if (absAngle < aspectThreshold) { 167 - return { anchor: 'right', x: shape.x + shape.width, y: clamp(cy, shape.y, shape.y + shape.height) }; 167 + return { anchor: 'right', x: shape.x + shape.width, y: clamp(py, shape.y, shape.y + shape.height) }; 168 168 } else if (absAngle > Math.PI - aspectThreshold) { 169 - return { anchor: 'left', x: shape.x, y: clamp(cy, shape.y, shape.y + shape.height) }; 169 + return { anchor: 'left', x: shape.x, y: clamp(py, shape.y, shape.y + shape.height) }; 170 170 } else if (angle < 0) { 171 - return { anchor: 'top', x: clamp(cx, shape.x, shape.x + shape.width), y: shape.y }; 171 + return { anchor: 'top', x: clamp(px, shape.x, shape.x + shape.width), y: shape.y }; 172 172 } else { 173 - return { anchor: 'bottom', x: clamp(cx, shape.x, shape.x + shape.width), y: shape.y + shape.height }; 173 + return { anchor: 'bottom', x: clamp(px, shape.x, shape.x + shape.width), y: shape.y + shape.height }; 174 174 } 175 175 }
+8 -6
src/slides/pptx-export.ts
··· 141 141 targetWidth = 960, 142 142 targetHeight = 540, 143 143 ): { x: number; y: number; width: number; height: number } { 144 - const scaleX = targetWidth / sourceWidth; 145 - const scaleY = targetHeight / sourceHeight; 144 + // Use uniform scaling to preserve aspect ratio (fit within target) 145 + const scale = Math.min(targetWidth / sourceWidth, targetHeight / sourceHeight); 146 + const offsetX = (targetWidth - sourceWidth * scale) / 2; 147 + const offsetY = (targetHeight - sourceHeight * scale) / 2; 146 148 return { 147 - x: Math.round(x * scaleX), 148 - y: Math.round(y * scaleY), 149 - width: Math.round(width * scaleX), 150 - height: Math.round(height * scaleY), 149 + x: Math.round(x * scale + offsetX), 150 + y: Math.round(y * scale + offsetY), 151 + width: Math.round(width * scale), 152 + height: Math.round(height * scale), 151 153 }; 152 154 } 153 155
+2 -1
src/slides/transitions.ts
··· 30 30 duration = 300, 31 31 easing: EasingType = 'ease-in-out', 32 32 ): TransitionConfig { 33 - return { type, duration: Math.max(0, Math.min(duration, 5000)), easing }; 33 + const d = Number.isFinite(duration) ? duration : 300; 34 + return { type, duration: Math.max(0, Math.min(d, 5000)), easing }; 34 35 } 35 36 36 37 /**