Skip to content

fix: use lookup table for badges char widths when canvas not available#2487

Open
t128n wants to merge 2 commits intonpmx-dev:mainfrom
t128n:fix/text-measurement-without-canvas-api
Open

fix: use lookup table for badges char widths when canvas not available#2487
t128n wants to merge 2 commits intonpmx-dev:mainfrom
t128n:fix/text-measurement-without-canvas-api

Conversation

@t128n
Copy link
Copy Markdown
Contributor

@t128n t128n commented Apr 12, 2026

🔗 Linked issue

Resolves #1601

🧭 Context

In production, measuring text with canvas is crashing, resulting in inaccurate fallback measurements:

overflowing badge

Introduced a character lookup table of "manually" measured character widths for more
accurate lookups.

📚 Description

Tweaked the estimateTextWidth function to use a on-character level lookup table for more accurate results when the Canvas API from @napi-rs/canvas is unavailable.
Lookup table derived from running

// ...
const ctx = createCanvas(1, 1).getContext('2d')
const chars = ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
ctx.font = BADGE_FONT_SHORTHAND
const entries = [...chars].map(ch => `'${ch === "'" ? "\\'" : ch === '\\' ? '\\\\' : ch}': ${Math.ceil(ctx.measureText(ch).width)}`)
console.log('default: {\n  ' + entries.join(', ') + '\n}')

locally, where fonts and the API are available.

Using a generous fallback for characters that aren't in the map, such as emojis.

📷 Comparison

Overflow / Long Labels

Case Prod PR
Long label
Long value
Long package name

Shields.io Style (?style=shieldsio)

Case Prod PR
Normal
Long label
Emoji label

Emojis

Case Prod PR
Emoji in label
Emoji in value
Multiple emojis
Emoji-only label

CJK Characters

Case Prod PR
Chinese label
Japanese label
Korean label
Mixed CJK + ASCII

Special & Punctuation Characters

Case Prod PR
Symbols
Narrow chars (iiiii)
Wide chars (WWWWW)
Mixed widths

Badge Types Smoke Test

Type Prod PR
version
license
downloads
size
types
deprecated

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Apr 12, 2026 0:18am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Apr 12, 2026 0:18am
npmx-lunaria Ignored Ignored Apr 12, 2026 0:18am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3dc6a077-5d8d-44d5-bc57-c97bf76ae350

📥 Commits

Reviewing files that changed from the base of the PR and between ae8981e and cbd6e61.

📒 Files selected for processing (1)
  • server/api/registry/badge/[type]/[...pkg].get.ts

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Improved accuracy of text width calculations for badges with enhanced character measurement across supported fonts.
    • Enhanced handling of special characters, including emojis and extended Unicode characters, in badge rendering.

Walkthrough

Replaced heuristic character-width estimation using character sets and fallback width buckets with static per-character lookup tables (CHAR_WIDTHS) for supported badge fonts. Updated estimateTextWidth function signature and logic to compute width via direct table lookups with a fallback constant for unmapped characters.

Changes

Cohort / File(s) Summary
Badge Text-Width Measurement
server/api/registry/badge/[type]/[...pkg].get.ts
Replaced character categorisation logic (narrow/medium/digit/uppercase/other buckets) with per-character lookup tables for default and shieldsio fonts. Added CHAR_WIDTH_FALLBACK constant for unmapped characters (emojis, CJK). Refactored estimateTextWidth to accept font parameter and sum character widths from lookup table.

Possibly related PRs

Suggested reviewers

  • danielroe
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: use lookup table for badges char widths when canvas not available' clearly and specifically describes the main change: replacing canvas-based text measurement with a character lookup table approach.
Description check ✅ Passed The description provides comprehensive context, including the linked issue, problem statement, solution approach, technical implementation details, and extensive visual comparisons demonstrating the fix across various test cases.
Linked Issues check ✅ Passed The PR directly addresses issue #1601 by implementing accurate character-width lookups to replace failing Canvas API calls, ensuring reliable badge rendering on Vercel with proper handling of ASCII, emojis, CJK characters, and punctuation.
Out of Scope Changes check ✅ Passed All changes remain within scope: replacing the character-width estimation logic with a lookup table approach in the badge route module, with no unrelated modifications to other areas.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@t128n t128n changed the title fix(badges): use lookup table for char widths when canvas not available fix: use lookup table for badges char widths when canvas not available Apr 12, 2026
@t128n t128n marked this pull request as ready for review April 12, 2026 12:15
@serhalp serhalp added needs review This PR is waiting for a review from a maintainer ux Related to wider UX decisions labels Apr 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review This PR is waiting for a review from a maintainer ux Related to wider UX decisions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Measuring text for the purpose of rendering badges fails on Vercel

2 participants