Skip to content

perf(a11y): pause WebGL and mascot decorative motion while hidden - #8438

Open
AmirrezaFarnamTaheri wants to merge 17 commits into
tinyhumansai:mainfrom
AmirrezaFarnamTaheri:upstream/perf-pause-hidden-decorative-motion-20261027
Open

AmirrezaFarnamTaheri wants to merge 17 commits into
tinyhumansai:mainfrom
AmirrezaFarnamTaheri:upstream/perf-pause-hidden-decorative-motion-20261027

Conversation

@AmirrezaFarnamTaheri

@AmirrezaFarnamTaheri AmirrezaFarnamTaheri commented Oct 27, 2026 •

Copy link
Copy Markdown

Summary

  • Use a shared visibility- and reduced-motion-aware subscription for decorative animations.
  • Pause WebGL animation frames without rebuilding the canvas and retain a stable rendered frame.
  • Pause and resume the mascot animation clock with accumulated active time instead of jumping or resetting.
  • Suspend idle-pose timers in hidden/reduced-motion views and restart without parallel timers.
  • Cover visibility/media-query transitions, listener cleanup, and mascot pause/resume regressions.

Problem

Decorative WebGL loops and mascot idle/clock animation could run while a page was hidden or the user requested reduced motion. Besides needless work, clocks can jump on resumption and idle timer changes can produce extra background animation.

Solution

Use useAnimationActivity based on useSyncExternalStore with document visibility and prefers-reduced-motion change subscriptions, then gate only decorative RAF/timers. Keep WebGL resources mounted, draw a stable frame while paused, and accumulate active elapsed time instead of including hidden duration. Keep business processing, model streaming and functional UI unaffected.

Submission Checklist

Items not applicable are marked N/A with a reason; no unverified test or coverage result is claimed.

  • Tests added or updated (happy path plus failure/edge cases): useAnimationActivity.test.tsx, useMascotClock.test.tsx, RiveMascot.test.tsx: document hidden and reduced-motion toggles, frame/timer cleanup, pause/resume continuity, and no extra idle poses.
  • Diff coverage ≥80%: exact-head CI Fast #40554797959 measured 95% (41/43 changed lines); full hosted checks passed. Local reruns are not claimed.
  • Coverage matrix updated: N/A — behavior changes within existing feature surfaces; no added, renamed, or retired feature leaf (existing IDs noted under Related).
  • All affected feature IDs listed in ## Related: 4.3.7 (Mascot Avatar Animation) and 4.3.4 (Subagent Mascot Visualization); decorative-only behavior change.
  • No new external network dependencies introduced: existing local frontend/core dependencies and contracts only.
  • Manual smoke checklist updated: N/A — no installer, release-cut, signing or distribution behavior changed; UI acceptance remains a reviewer follow-up.
  • Linked issue via Closes #NNN: N/A — no confirmed tracking issue to close; no invented issue reference.

Impact

Frontend desktop/web performance and accessibility. Less background CPU/GPU work and no unnecessary motion; visible active animation retains existing appearance. No backend, vendor, inference, or network behavior change.

Related

  • Affected feature IDs: 4.3.7 (Mascot Avatar Animation) and 4.3.4 (Subagent Mascot Visualization); decorative-only behavior change.
  • Closes: N/A — no linked issue.
  • Follow-up PR(s)/TODOs: verify full hosted CI and changed-line coverage; add browser/runtime acceptance when the changed surface warrants it.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A — none supplied.
  • URL: N/A — none supplied.

Commit & Branch

  • Branch: AmirrezaFarnamTaheri:upstream/perf-pause-hidden-decorative-motion-20261027
  • Commit SHA: 6666312d03bf599f09e360a69714731c8be751f8

Validation Run

  • Exact-head CI Fast: run #40554797959 passed on 6666312d03bf599f09e360a69714731c8be751f8.
  • Frontend typecheck, Prettier, and repository-gated frontend test lanes passed in hosted CI.
  • Focused coverage: pnpm --filter openhuman-app exec vitest run src/hooks/useAnimationActivity.test.tsx src/features/human/Mascot/useMascotClock.test.tsx src/features/human/Mascot/RiveMascot.test.tsx is included in the hosted Vitest suite (not run locally).
  • Rust fmt/check: N/A, no Rust source changes.
  • Tauri fmt/check: N/A, no Tauri source changes.

Validation Blocked

  • Local desktop/browser visual acceptance has not been completed in this session. Hosted CI passed; manual desktop/browser acceptance remains recommended during maintainer review. Review-ready is not merge approval.

Behavior Changes

  • Intended behavior change: Use a shared visibility- and reduced-motion-aware subscription for decorative animations.
  • User-visible effect: Frontend desktop/web performance and accessibility.

Parity Contract

  • Legacy behavior preserved: Use useAnimationActivity based on useSyncExternalStore with document visibility and prefers-reduced-motion change subscriptions, then gate only decorative RAF/timers.
  • Guard/fallback/dispatch parity checks: useAnimationActivity.test.tsx, useMascotClock.test.tsx, RiveMascot.test.tsx: document hidden and reduced-motion toggles, frame/timer cleanup, pause/resume continuity, and no extra idle poses.

Duplicate / Superseded PR Handling

Review readiness (2026-10-28)

  • CI Fast and PR Quality: successful on head 6666312d03bf.
  • Changed-line diff coverage: 95% (41/43 changed lines), above the 80% threshold.
  • Inline review threads: no unresolved threads at submission time.
  • Manual UI/device acceptance and maintainer approval remain open; no false completion claim.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 9 billable files and costs up to $2.25.

Or wait 50 seconds for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 80313cf4-7bbc-4eaa-a95d-7a528548ea48
Commits

Reviewing files that changed from the base of the PR and between e53cc0c and f06b8f5.

Files selected for processing: 9
  • app/src/components/RotatingTetrahedronCanvas.test.tsx
  • app/src/components/RotatingTetrahedronCanvas.tsx
  • app/src/features/human/Mascot/ManifestRiveMascot.test.tsx
  • app/src/features/human/Mascot/RiveMascot.test.tsx
  • app/src/features/human/Mascot/RiveMascot.tsx
  • app/src/features/human/Mascot/useMascotClock.test.tsx
  • app/src/features/human/Mascot/useMascotClock.ts
  • app/src/hooks/useAnimationActivity.test.tsx
  • app/src/hooks/useAnimationActivity.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@AmirrezaFarnamTaheri AmirrezaFarnamTaheri changed the title perf(a11y): pause decorative WebGL and mascot animation while hidden perf(a11y): pause WebGL and mascot decorative motion while hidden Oct 27, 2026
@AmirrezaFarnamTaheri
AmirrezaFarnamTaheri marked this pull request as ready for review October 28, 2026 09:15
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T09:23:41.602778Z 6666312 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@tinysweeper

tinysweeper Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Reviewed head: f06b8f5c0fdfd4b3c19eaffa337b0b606dca23a5

Verdict: Ready for maintainer review · Priority: none
Coverage: Reviewed 9 of 9 files.
Pull request purpose (title): perf(a11y): pause We…

Diagnostics and supporting details

Full summary

Pull request purpose (title): perf(a11y): pause WebGL and mascot decorative motion while hidden. This pull request pauses decorative animation work while the page is hidden or the user prefers reduced motion. It introduces a shared activity hook and threads it through the WebGL tetrahedron canvas, the mascot idle-pose rotation, and the mascot clock, with colocated tests.

Review snapshot

Change surface Files Review signal Count
Production 4 Active findings 0
Tests 5 Noted findings 0
Documentation 0 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

Adds a shared `useAnimationActivity` subscription based on `useSyncExternalStore` over document visibility and `prefers-reduced-motion` (app/src/hooks/useAnimationActivity.ts). Uses it to stop the WebGL render loop while keeping a static frame and retained scene in RotatingTetrahedronCanvas.tsx. Gates the mascot idle-pose scheduler in RiveMascot.tsx and accumulates active elapsed time in useMascotClock.ts so the clock does not jump or reset on resume. Adds tests for the hook, clock, RiveMascot idle rotation, ManifestRiveMascot, and the tetrahedron canvas.

Features

  • Added — Shared animation-activity subscription: Provides a single visibility- and reduced-motion-aware boolean that decorative animations can consume, with listener cleanup and legacy `addListener` fallback. (app/src/hooks/useAnimationActivity.ts, app/src/hooks/useAnimationActivity.test.tsx)
  • Modified — WebGL tetrahedron canvas pausing: Stops requesting animation frames while motion is disallowed but keeps the rendered scene and draws a static frame; resumes without rebuilding the WebGL scene. (app/src/components/RotatingTetrahedronCanvas.tsx, app/src/components/RotatingTetrahedronCanvas.tsx export default function RotatingTetrahedronCanvas({)
  • Modified — Mascot idle-pose rotation gating: Suspends the ambient idle-pose scheduler when animation activity is disallowed and restores it when activity returns. (app/src/features/human/Mascot/RiveMascot.tsx, app/src/features/human/Mascot/RiveMascot.tsx export const RiveMascot: FC<RiveMascotProps> = ({)
  • Modified — Mascot clock active-time accumulation: Accumulates only active elapsed time and holds the last frame while inactive, so the clock resumes without a jump or reset. (app/src/features/human/Mascot/useMascotClock.ts)

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

No active actionable findings.

Before merge

None.

Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 9 files; 0 findings. _The code index is behind this pull request (indexed at `03e62a25930d`), so retrieved context may be out of date._

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 9 files; 0 findings. _The code index is behind this pull request (indexed at `03e62a25930d`), so retrieved context may be out of date._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change adds a shared `useAnimationActivity` hook (visibility + prefers-reduced-motion) and threads it through the mascot clock, RiveMascot idle rotation, ManifestRiveMascot, and the tetrahedron canvas, with new colocated Vitest coverage for each path including the play/pause resume path and the no-WebGL error path. One gap stands out: `ManifestRiveMascot.tsx` is listed as a behaviour change and its new test drives `activity` on/off, but the diff shows no corresponding change to that component, and the diff's stated invariant that the idle scheduler is paused is not pinned by any assertion against the channels' behaviour. _The code index is behind this pull request (indexed at `03e62a25930d`), so retrieved context may be out of date._

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: Commits lane answered with zero findings, reporting no sensitive content in committed files.
  • Lane summary: No sensitive content in committed files. _The code index is behind this pull request (indexed at `03e62a25930d`), so retrieved context may be out of date._

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: Description lane answered with zero findings, finding the PR description consistent with the diff's decorative-animation gating, static-frame retention, and active-time accumulation.
  • Lane summary: The PR description matches the diff: it announces a shared visibility/reduced-motion hook feeding three decorative animation surfaces (WebGL canvas RAF loop, mascot idle-pose timers, mascot clock), and the diff adds exactly that plus tests. The described behaviour — pausing without rebuilding the scene, retaining a static frame, and accumulating active time instead of including hidden duration — is what the changed code implements, and the claimed feature IDs, CI notes, and N/A items are consistent with a frontend-only decorative change. Nothing in the diff contradicts the description or goes unmentioned in a significant way. _The code index is behind this pull request (indexed at `03e62a25930d`), so retrieved context may be out of date._
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.026800
  • Tokens: 582491 input · 8348 output · 134400 cached · 683 embedding
  • Updated: 2026-10-28T11:26:09Z
Head State Pass summary
f06b8f5c0fdf ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-28T11:26:09Z)

tinysweeper 0.1.2

@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: 6666312d03

ℹ️ 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".

setPoseRef.current = setPose;
useEffect(() => {
if (!idlePoseRotation || basePose !== 'idle') return;
if (!idlePoseRotation || !animationAllowed || basePose !== 'idle') return;

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 Apply the activity guard to manifest mascots

When a user has selected a manifest mascot, HumanPage renders ManifestRiveMascot instead of this component, so the new guard is bypassed as soon as its buffer loads. ManifestRiveStage still starts its idle-flourish timeout at ManifestRiveMascot.tsx:150-170, and ChannelDriver still starts auto-cycle intervals at lines 223-237, with no visibility or motion check. Those custom mascots therefore continue changing pose/channel while the document is hidden or prefers-reduced-motion is enabled; propagate animationAllowed to that stage and its channel drivers rather than guarding only the bundled path.

Useful? React with 👍 / 👎.

@tinysweeper tinysweeper 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.

tinysweeper found nothing blocking. Approving.

Diagnostics

Total spend: $0.0268

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Oct 28, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant