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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: medium · Type: a11y · Confidence: high
Location:
src/tile/MediaView.tsx:142-152,src/tile/MediaView.module.css:64-79src/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
AvatarDecorationcomponent explicitly suppresses them underprefers-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.tsxexplicitly checksuseReducedMotion()and renders onlychildren(no<img>) when the user has that preference — LOTUS_TODO.md even lists this as a shipped, deliberate a11y fix ("Avatar-decorationprefers-reduced-motion— DONE"). The EC in-callMediaView.tsxrenders<img src={decoration} …>unconditionally wheneveruseLotusDecoration(userId)returns a URL and the avatar (not video) is showing, with nomatchMedia('(prefers-reduced-motion: reduce)')guard and no such rule inMediaView.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 aprefers-reduced-motioncheck (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) inMediaView.tsx/useLotusDecorationand skip rendering.lotusDecorationwhen it matches, matching the rest of the Lotus theming stack's documented policy.Filed from the September 2026 audit (branch
lotus).