Skip to content

Conversation

@jonkafton
Copy link
Contributor

@jonkafton jonkafton commented Nov 7, 2025

What are the relevant tickets?

Closes https://github.com/mitodl/hq/issues/8971

Description (What does it do?)

Certificate PDF page layouts are constrained by height and elements are positions absolute.

We can not wrap longer names to multiple lines without changing the layout to accommodate.

This change makes an estimation on the width of the rendered name based on character count and scales the font size to ensure it fits on one line.

Screenshots (if appropriate):

Normal case:
image

Scaling starts around 30+ characters:
image

image image image image

Failure point around 98 characters (max scale down is 35%). The name below has 107 chars:
image

The MIT IS&T Data Warehouse FULL_NAME field can hold up to 90 characters: https://web.mit.edu/warehouse/metadata/fields/student_directory_full.html

From Sonnet 4.5:

Available data points

  1. General population:

    • Average full name: ~13–14 characters
    • 95% of names: ≤25 characters (older study, US-focused)
  2. MIT context:

    • Maximum: 90 characters (system limit)
    • International student body likely skews longer than general US averages

Realistic estimates for MIT

Given MIT's international population, a reasonable estimate:

  • 90th percentile: ~40–50 characters
  • 95th percentile: ~55–65 characters
  • 99th percentile: ~70–80 characters

How can this be tested?

@jonkafton jonkafton added the Needs Review An open Pull Request that is ready for review label Nov 7, 2025
@ahtesham-quraish ahtesham-quraish self-assigned this Nov 10, 2025
- Scaling factor of 0.8 emulates browser print scaling and better reflect the screen design
*/
export const pxToPt = (px: number): number => {
return px * (72 / 96) * 0.8
Copy link
Contributor

@ahtesham-quraish ahtesham-quraish Nov 10, 2025

Choose a reason for hiding this comment

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

You can clarify the intent of the scaling factor 0.8 (which is fine) by naming it:

const PRINT_SCALING_FACTOR = 0.8;
return px * (72 / 96) * PRINT_SCALING_FACTOR;

That way, future devs instantly know what it represents without reading the comment block.

// For Neue Haas Grotesk at 52px, approximate average char width is ~60% of font size
const avgCharWidth = baseFontSize * 0.6

const estimatedWidth = name.length * avgCharWidth
Copy link
Contributor

@ahtesham-quraish ahtesham-quraish Nov 10, 2025

Choose a reason for hiding this comment

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

If name is an empty string, estimatedWidth is 0, and scaleFactor stays 1.0. That’s fine — but you could explicitly handle it for clarity:

if (!name.trim()) return { fontSize: baseFontSize, top: baselineTop };

right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'll always have a name - not much point in setting a font size for printing nothing in any case.

const estimatedWidth = name.length * avgCharWidth

let scaleFactor = 1.0
if (estimatedWidth > maxWidth) {
Copy link
Contributor

@ahtesham-quraish ahtesham-quraish Nov 10, 2025

Choose a reason for hiding this comment

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

Suggestion:
Sometimes names are right at the edge of the maxWidth, so a tiny buffer (e.g. 95% of max width) ensures better visual balance: (I will reproduce it in local testing)

const effectiveMaxWidth = maxWidth * 0.95;
if (estimatedWidth > effectiveMaxWidth) {
  scaleFactor = Math.max(0.35, effectiveMaxWidth / estimatedWidth);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The max width already leaves some whitespace before the text overlays the badge, so we can render right up to it.

@jonkafton jonkafton merged commit 2403fb7 into main Nov 18, 2025
13 checks passed
@jonkafton jonkafton deleted the jk/8971-certificate-name-scaling branch November 18, 2025 14:29
@jonkafton jonkafton removed the Needs Review An open Pull Request that is ready for review label Nov 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants