diff --git a/packages/core/src/canvas/fills.ts b/packages/core/src/canvas/fills.ts index f014cc095..dee9638e3 100644 --- a/packages/core/src/canvas/fills.ts +++ b/packages/core/src/canvas/fills.ts @@ -105,9 +105,14 @@ interface PatternTileLayout { positions: Vector[] } -function patternAlignmentOffset(alignment: Fill['horizontalAlignment'], gap: number): number { - if (alignment === 'CENTER') return gap / 2 - if (alignment === 'END') return gap +function patternAlignmentOffset( + alignment: Fill['horizontalAlignment'], + gap: number, + sourceSize: number, + axis: 'x' | 'y' +): number { + if (alignment === 'CENTER') return axis === 'x' ? -gap / 2 : -sourceSize / 2 + if (alignment === 'END') return -gap return 0 } @@ -120,8 +125,8 @@ export function patternTileLayout(source: SceneNode, fill: Fill): PatternTileLay const gapY = scaledHeight * spacing.y const width = scaledWidth + gapX const height = scaledHeight + gapY - const x = patternAlignmentOffset(fill.horizontalAlignment, gapX) - const y = patternAlignmentOffset(fill.verticalAlignment, gapY) + const x = patternAlignmentOffset(fill.horizontalAlignment, gapX, scaledWidth, 'x') + const y = patternAlignmentOffset(fill.verticalAlignment, gapY, scaledHeight, 'y') const positions = [{ x, y }] if (fill.patternTileType === 'HORIZONTAL_HEXAGONAL') { diff --git a/tests/e2e/canvas/renderer-visuals.spec.ts-snapshots/pattern-fills-from-source-nodes-openpencil-darwin.png b/tests/e2e/canvas/renderer-visuals.spec.ts-snapshots/pattern-fills-from-source-nodes-openpencil-darwin.png index ac131ff73..4d831c72d 100644 Binary files a/tests/e2e/canvas/renderer-visuals.spec.ts-snapshots/pattern-fills-from-source-nodes-openpencil-darwin.png and b/tests/e2e/canvas/renderer-visuals.spec.ts-snapshots/pattern-fills-from-source-nodes-openpencil-darwin.png differ diff --git a/tests/engine/render/canvas/image-fill.test.ts b/tests/engine/render/canvas/image-fill.test.ts index 6d3536014..18a74ca53 100644 --- a/tests/engine/render/canvas/image-fill.test.ts +++ b/tests/engine/render/canvas/image-fill.test.ts @@ -42,7 +42,7 @@ describe('canvas pattern fills', () => { expect(layout).toEqual({ rect: { x: 0, y: 0, width: 50, height: 30 }, scale: 2, - positions: [{ x: 5, y: 10 }] + positions: [{ x: -5, y: -10 }] }) }) diff --git a/tests/fixtures/figma-oracles/visual-comparison-report.json b/tests/fixtures/figma-oracles/visual-comparison-report.json index ec603b56d..c58377f31 100644 --- a/tests/fixtures/figma-oracles/visual-comparison-report.json +++ b/tests/fixtures/figma-oracles/visual-comparison-report.json @@ -8,13 +8,15 @@ { "name": "pattern-visible-source-frame", "nodeId": "296784:2258", - "output": "/tmp/open-pencil-oracles/pattern-visible-source-norm", + "output": "/tmp/open-pencil-oracles/pattern-visible-source-tuned", "figmaSize": "190x110", "openPencilSize": "190x110", - "differentPixels": 13026, - "differentPercent": 62.33, - "rmseNormalized": 0.361297, - "finding": "This is the reliable pattern oracle: source and target are copied together and Figma renders the pattern. OpenPencil now resolves the source, but tile origin/spacing still differs from Figma." + "differentPixels": 7180, + "differentPercent": 34.35, + "rmseNormalized": 0.235698, + "previousDifferentPixels": 13026, + "previousDifferentPercent": 62.33, + "finding": "This is the reliable pattern oracle: source and target are copied together and Figma renders the pattern. OpenPencil resolves the source and now uses a closer Figma-like pattern origin, but exact row spacing/tile origin still differs." }, { "name": "rich-text-decorations", @@ -61,7 +63,7 @@ } ], "nextActions": [ - "Tune pattern tile origin and spacing against pattern-visible-source-frame.", + "Continue tuning pattern row spacing and tile origin against pattern-visible-source-frame.", "Use perceptual/color-tolerant image diff for mask comparisons instead of raw absolute-error counts.", "Tune rich text line metrics before treating underline placement diffs as actionable." ]