Skip to content

[TW-6448] fix(@ownmail/app): preserve transparent dark artwork - #293

Merged
AaronDDM merged 5 commits into
mainfrom
aaron/tw-6448-dark-transparent-artwork
Aug 20, 2026
Merged

[TW-6448] fix(@ownmail/app): preserve transparent dark artwork#293
AaronDDM merged 5 commits into
mainfrom
aaron/tw-6448-dark-transparent-artwork

Conversation

@AaronDDM

@AaronDDM AaronDDM commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • remove universal pale backings from email media in dark mode
  • classify low-color transparent brand artwork, including mid-tone saturated illustrations
  • lift dark and mid-tone artwork pixels for dark-surface contrast while preserving hue ordering and alpha
  • keep light mode and Original image pixels unchanged

Validation

  • pnpm lint (0 warnings)
  • pnpm --filter @ownmail/app typecheck
  • pnpm --filter @ownmail/app test (2,246 tests; 100% statements, branches, functions, and lines)
  • visually verified all 5 sender groups in the current 25-message Helix HTML corpus at mobile and desktop widths
  • verified all 13 matching transparent color-art images gain luminance with zero alpha changes, hue-order reversals, or light/Original changes
  • reported 112x112 workflow artwork improves from 5.86:1 to 8.45:1 minimum contrast on black while retaining its blue palette

Jira: TW-6448
Epic: TW-5882

@AaronDDM
AaronDDM marked this pull request as ready for review August 20, 2026 03:33
@AaronDDM
AaronDDM requested a review from radenkovic as a code owner August 20, 2026 03:33
@AaronDDM
AaronDDM requested a review from qasim-nylas August 20, 2026 03:33
qasim-nylas
qasim-nylas previously approved these changes Aug 20, 2026

@qasim-nylas qasim-nylas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM 👍

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d0651e5adb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread labs/ownmail/packages/app/src/features/mail/lib/email-render.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d25ed96f50

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread labs/ownmail/packages/app/src/features/mail/lib/email-render.ts
@AaronDDM
AaronDDM requested a review from qasim-nylas August 20, 2026 03:59
@AaronDDM
AaronDDM enabled auto-merge (squash) August 20, 2026 03:59
qasim-nylas
qasim-nylas previously approved these changes Aug 20, 2026

@qasim-nylas qasim-nylas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM 👍

@qasim-nylas qasim-nylas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM 👍

@AaronDDM
AaronDDM merged commit 227946f into main Aug 20, 2026
11 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09816c0127

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

:host([data-color-mode="original"][data-email-theme="light"]) .email-root{background:#fff!important;color:#1a1a1a!important;}
:host([data-dark-invert]) .email-root :where(img:is([src], [srcset]), video, svg, canvas){filter:invert(1) hue-rotate(180deg)!important;background-color:#f3f4f6!important;}
:host([data-email-theme="dark"]) .email-root :where(img[src*="/email-images/"], img[srcset*="/email-images/"]){background-color:#f3f4f6!important;}
:host([data-dark-invert]) .email-root :where(img:is([src], [srcset]), video, svg, canvas){filter:invert(1) hue-rotate(180deg)!important;}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retain contrast backing for transparent video

When an email contains an alpha-capable video or a video with a dark transparent poster, this rule counter-inverts the media to its original dark colors while the host inversion makes the message canvas black. Unlike img, video is neither pixel-sampled nor covered by the retained svg, canvas backing, so the poster or transparent frames can become effectively invisible. Retain a scoped backing for video or extend the conditional inspection to its poster and frames.

Useful? React with 👍 / 👎.

private readonly handleMediaSettled = (event: Event): void => {
if (event.target instanceof HTMLImageElement) {
const image = event.target
if (event.type === 'load') updateDarkImageBacking(image, this.darkImageBackingEnabled())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Re-evaluate backing across animated image frames

For an animated GIF, WebP, or APNG whose initial frame is light or opaque but a later frame is dark and transparent, this samples only the frame shown when load fires; frame advances do not emit additional load events, so the backing attribute remains absent and later artwork can disappear against the black canvas. Fresh evidence in the final code is that updateDarkImageBacking is invoked only from this one-time load handler. Animated formats need a conservative backing or frame-aware re-evaluation.

Useful? React with 👍 / 👎.

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.

2 participants