diff --git a/apps/sim/lib/branding/wordmark.test.ts b/apps/sim/lib/branding/wordmark.test.ts index b73dd955804..e2fe70129e2 100644 --- a/apps/sim/lib/branding/wordmark.test.ts +++ b/apps/sim/lib/branding/wordmark.test.ts @@ -4,10 +4,12 @@ import { readFileSync } from 'node:fs' import path from 'node:path' import { describe, expect, it } from 'vitest' -import { EMAIL_WORDMARK_SIZE, WORDMARK_PATHS, WORDMARK_VIEW_BOX } from '@/lib/branding/wordmark' - -/** Email clients do no responsive image selection, so the asset carries retina detail itself. */ -const MIN_RETINA_SCALE = 2 +import { + EMAIL_WORDMARK_CANVAS, + EMAIL_WORDMARK_SIZE, + WORDMARK_PATHS, + WORDMARK_VIEW_BOX, +} from '@/lib/branding/wordmark' const WORDMARK_PNG = path.join( import.meta.dirname, @@ -27,27 +29,27 @@ function readPngSize(file: string): { width: number; height: number } { } describe('email wordmark asset', () => { - it('out-resolves the box the email header renders it in', () => { - const { width, height } = readPngSize(WORDMARK_PNG) - expect(width).toBeGreaterThanOrEqual(EMAIL_WORDMARK_SIZE.width * MIN_RETINA_SCALE) - expect(height).toBeGreaterThanOrEqual(EMAIL_WORDMARK_SIZE.height * MIN_RETINA_SCALE) + it('keeps the canvas every email already sent was measured against', () => { + expect(readPngSize(WORDMARK_PNG)).toEqual({ + width: EMAIL_WORDMARK_CANVAS.width, + height: EMAIL_WORDMARK_CANVAS.height, + }) }) - it('is committed at the aspect ratio the header displays it at', () => { - const { width, height } = readPngSize(WORDMARK_PNG) - const assetAspect = width / height + it('renders undistorted in the box the header displays it in', () => { const boxAspect = EMAIL_WORDMARK_SIZE.width / EMAIL_WORDMARK_SIZE.height - expect(Math.abs(assetAspect - boxAspect) / boxAspect).toBeLessThan(0.01) + const canvasAspect = EMAIL_WORDMARK_CANVAS.width / EMAIL_WORDMARK_CANVAS.height + expect(Math.abs(boxAspect - canvasAspect) / canvasAspect).toBeLessThan(0.01) }) - it('renders the mark at the brand outlines aspect ratio, within a rounding pixel', () => { - const boxAspect = EMAIL_WORDMARK_SIZE.width / EMAIL_WORDMARK_SIZE.height - const viewBoxAspect = WORDMARK_VIEW_BOX.width / WORDMARK_VIEW_BOX.height - expect(Math.abs(boxAspect - viewBoxAspect) / viewBoxAspect).toBeLessThan(0.01) + it('out-resolves that box, since email clients do no responsive selection', () => { + expect(EMAIL_WORDMARK_CANVAS.width).toBeGreaterThanOrEqual(EMAIL_WORDMARK_SIZE.width * 2) + expect(EMAIL_WORDMARK_CANVAS.height).toBeGreaterThanOrEqual(EMAIL_WORDMARK_SIZE.height * 2) }) it('carries every glyph of the logotype', () => { expect(WORDMARK_PATHS).toHaveLength(4) for (const d of WORDMARK_PATHS) expect(d.startsWith('M')).toBe(true) + expect(WORDMARK_VIEW_BOX.width).toBeGreaterThan(WORDMARK_VIEW_BOX.height) }) }) diff --git a/apps/sim/lib/branding/wordmark.ts b/apps/sim/lib/branding/wordmark.ts index 580fbf17c55..a02bf9cb782 100644 --- a/apps/sim/lib/branding/wordmark.ts +++ b/apps/sim/lib/branding/wordmark.ts @@ -17,17 +17,29 @@ export const WORDMARK_PATHS: readonly string[] = [ 'M179.43 212H149.16V49.76C153.76 51.91 158.88 53.12 164.29 53.12C169.7 53.12 174.83 51.91 179.43 49.76V212Z', ] +/** + * Canvas of `public/brand/color/email/wordmark.png`, which the header renders + * instead of these paths because email clients strip inline SVG. + * + * **These proportions are frozen.** A sent email is immutable — it keeps the + * `width`/`height` it was sent with and refetches this URL forever — so an + * export whose canvas is shaped differently would stretch the mark in every + * message already delivered. Re-export onto this canvas (the outlines centered + * at their own aspect, filled with the email palette's `textBody`) and the same + * file keeps serving old and new mail alike. + */ +export const EMAIL_WORDMARK_CANVAS = { width: 272, height: 164 } as const + /** * Display box for the email header wordmark. * * The landing navbar sizes the mark at its neighbouring text plus 2px above and * below (18px ink against 14px chip labels). Email body copy is 16px, so the - * mark stands 20px tall; the width follows the view box. Both dimensions are - * pinned because email clients do no responsive image selection. + * mark wants to stand ~20px tall. The canvas insets the outlines, so a 26px box + * renders 20.7px of ink; the width follows {@link EMAIL_WORDMARK_CANVAS}. Both + * dimensions are pinned because email clients do no responsive image selection. * - * The header renders `public/brand/color/email/wordmark.png` rather than these - * paths, because email clients strip inline SVG. That file is these outlines - * filled with the email palette's `textBody`, rasterized at 4x so the mark - * stays crisp on retina and this box can be retuned without re-exporting it. + * Retuning this box is safe on its own — the canvas is 6x the box, so the mark + * stays crisp, and older mail keeps rendering against its own numbers. */ -export const EMAIL_WORDMARK_SIZE = { width: 42, height: 20 } as const +export const EMAIL_WORDMARK_SIZE = { width: 43, height: 26 } as const diff --git a/apps/sim/public/brand/color/email/wordmark.png b/apps/sim/public/brand/color/email/wordmark.png index 6851edd5b39..582fac9fe93 100644 Binary files a/apps/sim/public/brand/color/email/wordmark.png and b/apps/sim/public/brand/color/email/wordmark.png differ