In-call avatar decoration (animated APNG) ignores prefers-reduced-motion, unlike the host renderer #19

Closed
opened 2026-09-12 02:13:07 -04:00 by jared · 0 comments
Owner

Severity: medium · Type: a11y · Confidence: high

Location: src/tile/MediaView.tsx:142-152, src/tile/MediaView.module.css:64-79
src/tile/MediaView.tsx:95,142-152, src/lotus/lotusDecorations.ts (no motion check anywhere in the module)

Problem

decorations are animated APNGs. cinny's own AvatarDecoration component explicitly suppresses them under prefers-reduced-motion (/root/code/cinny/src/app/components/avatar-decoration/AvatarDecoration.tsx:23-28, shipped as LOTUS_TODO item P2), but the fork's in-call renderer has no such guard, and neither the CSS nor the host push filters by the preference. A user with reduced motion enabled therefore gets animated overlays on every camera-off tile — the densest possible concentration of them — which is exactly the case the cinny fix was written for.

Related finding: Lotus decorations are animated APNGs (per cinny's own comment: "Decorations are animated APNGs with no static asset to freeze to"). The host-side AvatarDecoration.tsx explicitly checks useReducedMotion() and renders only children (no <img>) when the user has that preference — LOTUS_TODO.md even lists this as a shipped, deliberate a11y fix ("Avatar-decoration prefers-reduced-motion — DONE"). The EC in-call MediaView.tsx renders <img src={decoration} …> unconditionally whenever useLotusDecoration(userId) returns a URL and the avatar (not video) is showing, with no matchMedia('(prefers-reduced-motion: reduce)') guard and no such rule in MediaView.module.css. A user who opted out of motion on the host still gets animated decorations inside every video call tile.

How to trigger

enable "reduce motion" in the OS, join a call where several participants have decorations and cameras off.

Also: Set OS/browser prefers-reduced-motion: reduce, join a call where any participant has a decoration and their camera is off (or hasn't started).

Suggested fix

wrap the <img> in a prefers-reduced-motion check (media query hiding .lotusDecoration, matching cinny's behaviour of rendering just the avatar).

Also: Mirror the host's guard — read matchMedia('(prefers-reduced-motion: reduce)') (or a small shared hook) in MediaView.tsx/useLotusDecoration and skip rendering .lotusDecoration when it matches, matching the rest of the Lotus theming stack's documented policy.


Filed from the September 2026 audit (branch lotus).

**Severity:** medium · **Type:** a11y · **Confidence:** high **Location:** `src/tile/MediaView.tsx:142-152`, `src/tile/MediaView.module.css:64-79` `src/tile/MediaView.tsx:95,142-152`, `src/lotus/lotusDecorations.ts` (no motion check anywhere in the module) ### Problem decorations are animated APNGs. cinny's own `AvatarDecoration` component explicitly suppresses them under `prefers-reduced-motion` (`/root/code/cinny/src/app/components/avatar-decoration/AvatarDecoration.tsx:23-28`, shipped as LOTUS_TODO item P2), but the fork's in-call renderer has no such guard, and neither the CSS nor the host push filters by the preference. A user with reduced motion enabled therefore gets animated overlays on every camera-off tile — the densest possible concentration of them — which is exactly the case the cinny fix was written for. **Related finding:** Lotus decorations are animated APNGs (per cinny's own comment: "Decorations are animated APNGs with no static asset to freeze to"). The host-side `AvatarDecoration.tsx` explicitly checks `useReducedMotion()` and renders only `children` (no `<img>`) when the user has that preference — LOTUS_TODO.md even lists this as a shipped, deliberate a11y fix ("Avatar-decoration `prefers-reduced-motion` — DONE"). The EC in-call `MediaView.tsx` renders `<img src={decoration} …>` unconditionally whenever `useLotusDecoration(userId)` returns a URL and the avatar (not video) is showing, with no `matchMedia('(prefers-reduced-motion: reduce)')` guard and no such rule in `MediaView.module.css`. A user who opted out of motion on the host still gets animated decorations inside every video call tile. ### How to trigger enable "reduce motion" in the OS, join a call where several participants have decorations and cameras off. Also: Set OS/browser `prefers-reduced-motion: reduce`, join a call where any participant has a decoration and their camera is off (or hasn't started). ### Suggested fix wrap the `<img>` in a `prefers-reduced-motion` check (media query hiding `.lotusDecoration`, matching cinny's behaviour of rendering just the avatar). Also: Mirror the host's guard — read `matchMedia('(prefers-reduced-motion: reduce)')` (or a small shared hook) in `MediaView.tsx`/`useLotusDecoration` and skip rendering `.lotusDecoration` when it matches, matching the rest of the Lotus theming stack's documented policy. --- _Filed from the September 2026 audit (branch `lotus`)._
jared added this to the EC fork audit 2026-09 · Medium & Low milestone 2026-09-12 02:13:07 -04:00
jared added the priority: mediuma11yarea: decorations labels 2026-09-12 02:13:07 -04:00
jared self-assigned this 2026-09-12 02:13:07 -04:00
jared closed this issue 2026-09-13 01:22:52 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-11-14
Dependencies

No dependencies set.

Reference: LotusGuild/element-call#19