Skip to content

fix: render piece SVGs at export resolution for crisp high-res output - #219

Merged
BilgeGates merged 2 commits into
masterfrom
fix/high-res-piece-export
Aug 3, 2026
Merged

fix: render piece SVGs at export resolution for crisp high-res output#219
BilgeGates merged 2 commits into
masterfrom
fix/high-res-piece-export

Conversation

@BilgeGates

Copy link
Copy Markdown
Member

What & why

High-res export now renders the embedded piece SVGs at the target output pixel size instead of their source intrinsic size. Sets with a low intrinsic resolution (e.g. california at 100px) were upscaled by browsers that rasterize nested SVG at its intrinsic size, which produces a soft image in high-DPI exports; the pieces are now resized to the computed output size (clamped 64–2048px) while never shrinking below the set's own artwork, so rasterization stays sharp in any browser and larger sets keep their supersampling advantage.

Checklist

  • pnpm validate passes locally
  • No any / @ts-ignore / non-null ! introduced
  • Screenshots or a screen recording added — only if this changes the UI

Copilot AI review requested due to automatic review settings August 3, 2026 10:22
@github-actions github-actions Bot added Bug Something is not working correctly area: export Canvas and SVG export pipeline labels Aug 3, 2026
@BilgeGates
BilgeGates force-pushed the fix/high-res-piece-export branch from f0a5ee8 to fc3ca28 Compare August 3, 2026 10:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the SVG export pipeline so embedded piece SVGs are resized to an intended export pixel size before being inlined, improving sharpness when the overall SVG is rasterized at high resolution.

Changes:

  • Passes a computed target size into imageToEmbeddableDataURL() so fetched SVG pieces can be resized before base64-inlining.
  • Adds intrinsicPxOf() (with tests) and resize/clamp logic for inlined SVG sources.
  • Includes broad formatting changes (quotes/trailing commas) in the touched utils.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/shared/utils/svgExporter.ts Computes a target piece size and forwards it into the piece inlining path during SVG generation.
src/shared/utils/pieceUtils.ts Adds intrinsic-size detection and conditional resizing for fetched SVG piece sources; updates data URL caching keying.
src/shared/utils/pieceUtils.test.ts Adds unit tests for intrinsicPxOf() parsing/conversion behavior.
Suppressed comments (3)

src/shared/utils/svgExporter.ts:4

  • This file was reformatted with double quotes and trailing commas, but the repo Prettier config sets singleQuote: true and trailingComma: "none" (.prettierrc). This will keep the file inconsistent with the rest of src/shared/utils and can break format/lint checks; please run Prettier or revert to the configured style.

This issue also appears on line 82 of the same file.

import { ChessBoard, isChessBoard } from '@app-types';

import {
  getDisplayCoordinates,

src/shared/utils/pieceUtils.ts:5

  • This file now uses double quotes and trailing commas, which conflicts with the repo Prettier config (singleQuote: true, trailingComma: "none" in .prettierrc) and the surrounding utils code. Please reformat with the repo formatter to avoid churn and potential CI format failures.
import { PIECE_SET_POPULARITY, PIECE_SETS as ALL_PIECE_SETS } from '@constants';
import type { PieceSet } from '@app-types';
import { logger } from './logger';

// Types

src/shared/utils/svgExporter.ts:82

  • pieceOutputPx is currently calculated using constants that effectively assume the 4× (1200 DPI) preset and ignore exportQuality. For lower quality presets this oversizes the embedded piece SVGs (larger base64, more memory/CPU) and no longer matches the actual raster target square size used by calculateRenderSurfaceSize().
    throw new Error('Invalid FEN: unable to parse board');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +214 to +225
function resizePieceSvg(svgText: string, targetPx: number): string {
const size = String(Math.round(targetPx));
const resized = svgText.replace(/<svg([^>]*?)>/i, (_match, attrs: string) => {
let next = attrs;
next = next.replace(/\s+width\s*=\s*"[^"]*"/i, ` width="${size}"`);
next = next.replace(/\s+height\s*=\s*"[^"]*"/i, ` height="${size}"`);
if (!/\swidth\s*=/.test(next)) next += ` width="${size}"`;
if (!/\sheight\s*=/.test(next)) next += ` height="${size}"`;
return `<svg${next}>`;
});
return resized === svgText ? svgText : resized;
}
Comment thread src/shared/utils/pieceUtils.test.ts Outdated
Copilot AI review requested due to automatic review settings August 3, 2026 10:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 3, 2026 10:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@BilgeGates
BilgeGates merged commit 41ef83a into master Aug 3, 2026
10 checks passed
@BilgeGates
BilgeGates deleted the fix/high-res-piece-export branch August 3, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: export Canvas and SVG export pipeline Bug Something is not working correctly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants