diff --git a/packages/core/src/parsers/htmlParser.test.ts b/packages/core/src/parsers/htmlParser.test.ts
index 119284df9..b913deb5b 100644
--- a/packages/core/src/parsers/htmlParser.test.ts
+++ b/packages/core/src/parsers/htmlParser.test.ts
@@ -257,6 +257,42 @@ describe("parseHtml", () => {
expect(result.resolution).toBe("portrait-4k");
});
+ it("classifies 1440p (QHD) as landscape, not landscape-4k", () => {
+ // Regression: an earlier `>= 2560` cutoff misclassified QHD compositions
+ // as 4K. The current rule uses the canonical 4K long-side (3840) so
+ // 2560×1440 stays in the landscape preset.
+ const html = `
+
+
+
+
+
+ `;
+ const result = parseHtml(html);
+
+ expect(result.resolution).toBe("landscape");
+ });
+
+ it("classifies square compositions as portrait by convention", () => {
+ // 1080×1080 has no obvious orientation. The parser collapses the tie to
+ // portrait — same bias the prior `w > h ? landscape : portrait` ternary
+ // had. Pinning so a future refactor doesn't silently flip it.
+ const html = `
+
+
+
+
+
+ `;
+ const result = parseHtml(html);
+
+ expect(result.resolution).toBe("portrait");
+ });
+
it("extracts x, y, scale, opacity from data attributes", () => {
const html = `
diff --git a/packages/core/src/parsers/htmlParser.ts b/packages/core/src/parsers/htmlParser.ts
index a8eb9b7ae..ba4c65ffb 100644
--- a/packages/core/src/parsers/htmlParser.ts
+++ b/packages/core/src/parsers/htmlParser.ts
@@ -143,9 +143,18 @@ function parseResolutionFromHtml(doc: Document): CanvasResolution | null {
}
function resolveResolutionFromDimensions(width: number, height: number): CanvasResolution {
+ // `width === height` (square) falls into the portrait branch by convention —
+ // the same bias the previous `w > h ? landscape : portrait` ternary used.
+ // Square compositions are rare; pick portrait-as-default so we don't surprise
+ // the existing call sites that depend on this behavior.
const isLandscape = width > height;
const longSide = Math.max(width, height);
- const isUhd = longSide >= 2560;
+ // UHD cutoff is the long side of `landscape-4k` / `portrait-4k` (3840). A
+ // looser threshold (e.g. ≥ 2560) would silently misclassify QHD/1440p
+ // (2560×1440) as 4K, which is the wrong default for a common authoring
+ // resolution closer to 1080p than to UHD. Authors who genuinely want the
+ // 4K preset can still set `data-resolution="landscape-4k"` explicitly.
+ const isUhd = longSide >= 3840;
if (isLandscape) return isUhd ? "landscape-4k" : "landscape";
return isUhd ? "portrait-4k" : "portrait";
}