fix(13): reduce field heights, nudge y-offset, tighten height prompt guidance

- Max heights reduced: text/date 16pt, initials 18pt, signature 26pt
- 0.5% y nudge pushes fields onto the underline instead of floating above it
- Prompt specifies 1.2% height for text/date, 1.8% for signatures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chandler Copeland
2026-03-21 17:49:11 -06:00
parent 48788dea23
commit 8ac5acb486

View File

@@ -41,11 +41,14 @@ export function aiCoordsToPagePdfSpace(
const screenY = (coords.yPct / 100) * pageHeight; // screen Y from top
const x = screenX;
// Nudge yPct down by 0.5% so the field sits on the underline rather than floating above it.
// AI tends to report the top of the blank area; we want the field aligned to the line itself.
const nudgedScreenY = screenY + pageHeight * 0.005;
// PDF y = distance from BOTTOM. screenY is from top, so flip:
// pdfY = pageHeight - screenY - fieldHeight (bottom edge of field)
// Clamp to [0, pageHeight - fieldHeight] so AI coords near page edges
// don't produce negative y values that render outside the canvas.
const rawY = pageHeight - screenY - fieldHeight;
const rawY = pageHeight - nudgedScreenY - fieldHeight;
const y = Math.max(0, Math.min(rawY, pageHeight - fieldHeight));
return { x, y, width: fieldWidth, height: fieldHeight };
@@ -145,8 +148,9 @@ POSITIONING AND SIZING:
- xPct and yPct are percentages from the TOP-LEFT of that specific page image
- Place the field AT the blank underline — align it to sit on top of the line
- For a row like "Signature __________ Date _______", create TWO separate fields: one for the signature blank and one for the date blank, each at their own x position
- widthPct: match the visual width of the underline — short blanks get small widths, long signature lines get wider
- heightPct: keep fields thin — signature/text ~2.5%, initials/date ~2%
- widthPct: match the visual width of the underline — short blanks get small widths (5-15%), long lines wider (20-30%)
- heightPct: THIN — use 1.2% for text/date/initials, 1.8% for signatures. Fields must not overlap the text above the blank.
- yPct: point to the underline itself. The field sits ON the blank line. If you place it too high it will cover the printed text above.
- Do NOT place checkbox fields
PREFILL:
@@ -192,13 +196,13 @@ PREFILL:
// Use AI-estimated size, clamped to type-appropriate min/max
const sizeLimits: Record<SignatureFieldType, { minW: number; maxW: number; minH: number; maxH: number }> = {
'client-signature': { minW: 100, maxW: 250, minH: 20, maxH: 40 },
'agent-signature': { minW: 100, maxW: 250, minH: 20, maxH: 40 },
'initials': { minW: 36, maxW: 80, minH: 16, maxH: 28 },
'agent-initials': { minW: 36, maxW: 80, minH: 16, maxH: 28 },
'date': { minW: 60, maxW: 130, minH: 14, maxH: 24 },
'text': { minW: 60, maxW: 280, minH: 14, maxH: 24 },
'checkbox': { minW: 16, maxW: 24, minH: 16, maxH: 24 },
'client-signature': { minW: 100, maxW: 250, minH: 16, maxH: 26 },
'agent-signature': { minW: 100, maxW: 250, minH: 16, maxH: 26 },
'initials': { minW: 30, maxW: 70, minH: 12, maxH: 18 },
'agent-initials': { minW: 30, maxW: 70, minH: 12, maxH: 18 },
'date': { minW: 55, maxW: 120, minH: 12, maxH: 16 },
'text': { minW: 40, maxW: 260, minH: 12, maxH: 16 },
'checkbox': { minW: 14, maxW: 20, minH: 14, maxH: 20 },
};
const lim = sizeLimits[aiField.fieldType] ?? sizeLimits['text'];
const width = Math.max(lim.minW, Math.min(rawW, lim.maxW));