Skip to content

feat(home): scroll gravity toward completed acts#208

Merged
kilbot merged 3 commits into
mainfrom
scroll-story-act-gravity
Jul 2, 2026
Merged

feat(home): scroll gravity toward completed acts#208
kilbot merged 3 commits into
mainfrom
scroll-story-act-gravity

Conversation

@kilbot

@kilbot kilbot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Owner ask: completed acts should have more "weight" than transitions when scrolling the story. This is the scrollytelling settle-assist pattern (GSAP ScrollTrigger's snap; CSS proximity snapping is the platform cousin but its radius isn't tunable) — hand-rolled on motion's animate, no new dependency.

Behaviour

  • When scrolling comes to rest within 0.05 progress (~a fifth of a viewport) of an act's composed plateau (0.40, 0.64, 0.95 — act 1 is the top of the page), the remaining distance eases there over 550ms with a soft curve
  • Mid-transition rests are left exactly where the user stopped — the pull only exists near plateaus
  • The user always wins: wheel/touch/keydown cancels the settle instantly; a dead zone prevents re-trigger loops; scrollend where supported with a debounced-scroll fallback; disabled under prefers-reduced-motion

Evidence

Real-Chromium probe: rest at 0.37 → settles 0.400; rest at 0.67 → settles 0.640; rest at 0.52 (transition) → stays 0.520. Unit tests cover the catch/dead-zone/nearest-hold maths. Full suite green, lint clean.

Note: ACT_HOLDS/CATCH_RADIUS in act-gravity.ts are the tuning knobs; if #204 (shader) merges first this rebases trivially (disjoint regions of scroll-story.tsx).

Summary by CodeRabbit

  • New Features

    • Enhanced the home scroll story’s pinned scrolling with “scroll gravity” snapping to key positions using smooth post-scroll settling.
    • Improved reduced-motion behavior by disabling auto-settling and respecting user input for quicker responsiveness.
  • Bug Fixes

    • Prevents re-triggering when already aligned with a target snap point.
    • More accurately selects the nearest snap point when multiple targets are within range.
    • Uses modern scroll-end behavior when available, with a safer fallback otherwise.
  • Tests

    • Added coverage for snapping rules and settling/cancellation scenarios, including reduced-motion and scroll-end paths.

Settle-assist for the pinned story (owner: transitions and completes felt
equal). When scrolling rests within a tunable catch radius (0.05 progress)
of an act's hold plateau (0.40 / 0.64 / 0.95), the last stretch eases to
the plateau over 550ms. scrollend where supported, debounced scroll as
fallback; any wheel/touch/key input cancels instantly; dead zone prevents
re-trigger loops; reduced motion disables it. Verified empirically in
Chromium: 0.37→0.400, 0.67→0.640, mid-transition 0.52 stays.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d74202c-2852-46c7-9404-a9b8a93ac66e

📥 Commits

Reviewing files that changed from the base of the PR and between 5f9ecae and db770a4.

📒 Files selected for processing (2)
  • src/components/home/scroll-story/act-gravity.test.ts
  • src/components/home/scroll-story/act-gravity.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/home/scroll-story/act-gravity.test.ts

📝 Walkthrough

Walkthrough

Adds an act-gravity module with hold snapping and settle behavior, wires it into the pinned scroll story, and expands tests for the hook and motion mock.

Changes

Scroll Gravity Feature

Layer / File(s) Summary
Act hold constants and nearestHold logic
src/components/home/scroll-story/act-gravity.ts
Defines ACT_HOLDS, CATCH_RADIUS, and DEAD_ZONE, and adds nearestHold(progress) to pick the closest hold within range.
useActGravity hook implementation
src/components/home/scroll-story/act-gravity.ts
Implements reduced-motion gating, scrollend/debounced settling, animated scrollTo updates, input cancellation, and cleanup.
scroll-story integration
src/components/home/scroll-story/scroll-story.tsx
Imports and invokes useActGravity with the scroller ref and scroll progress motion value.
act-gravity test suite
src/components/home/scroll-story/act-gravity.test.ts
Adds nearestHold coverage, harness/utilities, and hook tests for fallback settle, scrollend, reduced motion, and cancellation.
scroll-story mock and animate tests
src/components/home/scroll-story/scroll-story.test.tsx
Updates the motion/react mock with animate, clears mock state, and adds an export-shape assertion.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main home scroll-gravity behavior added by the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch scroll-story-act-gravity

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

@greptile-apps greptile-apps 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.

kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🚀 Preview: https://wcpos-k1kopu0b9-wcpos.vercel.app

@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: 767b15e137

ℹ️ 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 src/components/home/scroll-story/act-gravity.ts
Comment thread src/components/home/scroll-story/act-gravity.ts

@greptile-apps greptile-apps 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.

kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@wcpos-bot

wcpos-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Fixed the remaining actionable review threads in commit 5f9ecae.

Thread File Issue Decision Commit
discussion_r3514681681 scroll-story.test.tsx motion/react test mock was missing the new animate export used by ScrollStory load. Fixed: added the animate stub and regression assertion. 5f9ecae
discussion_r3514681689 act-gravity.ts cancel() left a fallback debounce timer alive after user input. Fixed: clears and resets the pending debounce handle; added regression coverage. 5f9ecae

Skipped threads: none.

Verification:

  • pnpm install --frozen-lockfile: passed
  • pnpm lint: passed with 5 existing warnings outside this change
  • pnpm exec tsc --noEmit: passed
  • pnpm test:unit: passed, 139 files / 960 tests
  • pnpm test:e2e --project=chromium: blocked locally before app code ran because Chromium cannot load libglib-2.0.so.0 in this environment

Post-push unresolved inline thread count before resolving: 2.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🚀 Preview: https://wcpos-a3zsgyzaa-wcpos.vercel.app

@wcpos-bot

wcpos-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review-thread follow-up for current head 5f9ecae: no new commit was needed in this round because the managed workspace is already at the review-fix commit and both inline threads are resolved.

Thread File Issue Decision Commit
discussion_r3514681681 scroll-story.test.tsx motion/react test mock needed the new animate export used through ScrollStory. Fixed already on current head; GraphQL thread state is resolved. 5f9ecae
discussion_r3514681689 act-gravity.ts cancel() needed to clear the pending fallback debounce timer. Fixed already on current head; GraphQL thread state is resolved. 5f9ecae

Skipped threads: none; fresh unresolved inline review-thread inventory returned 0 rows.

CI / validation status:

  • Remote GitHub checks: Test, E2E Tests, Deploy Preview, CodeQL, and CodeQL analyses are passing; CodeRabbit status is still pending.
  • Local pnpm install --frozen-lockfile: passed.
  • Local pnpm lint: passed with 5 existing warnings outside the scroll-story change.
  • Local pnpm exec tsc --noEmit: passed.
  • Local pnpm test:unit: passed, 139 files / 960 tests.
  • Local pnpm test:e2e --project=chromium: blocked by environment/browser dependency; Chromium could not load libglib-2.0.so.0 and exited 1. Remote E2E is passing on GitHub Actions.

Remaining unresolved inline review threads after final GraphQL inventory: 0.

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

🧹 Nitpick comments (2)
src/components/home/scroll-story/act-gravity.test.ts (2)

72-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Only cancellation is tested; the actual settle mechanics are not.

The single useActGravity test verifies debounce cancellation on user input, but nothing here exercises the "pull toward plateau" behavior itself (hold selection → animate/window.scrollTo invocation), the scrollend-available path, or the prefers-reduced-motion early-return. Given this is the PR's core new behavior, consider adding tests that stub window.scrollTo/Element.prototype.getBoundingClientRect and assert a settle is triggered when scrolling stops near a hold (and skipped when reduced-motion is set).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/home/scroll-story/act-gravity.test.ts` around lines 72 - 94,
The current useActGravity coverage only checks debounce cancellation, so add
tests that exercise the actual settle behavior in GravityHarness/useActGravity
by stubbing window.scrollTo and Element.prototype.getBoundingClientRect and
asserting a hold selection triggers the “pull toward plateau” path when
scrolling stops; also add coverage for the scrollend-supported branch and the
prefers-reduced-motion early return so the main behavior and skip paths are both
verified.

30-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Dead-zone test relies on an unexported magic number.

DEAD_ZONE (0.004) isn't exported from act-gravity.ts, so line 33's hold + 0.002 is a magic number that silently decouples from the real constant if it ever changes.

♻️ Suggested fix
 import {
   ACT_HOLDS,
   CATCH_RADIUS,
+  DEAD_ZONE,
   nearestHold,
   useActGravity,
 } from './act-gravity'
-      expect(nearestHold(hold + 0.002)).toBeNull()
+      expect(nearestHold(hold + DEAD_ZONE / 2)).toBeNull()

(Requires exporting DEAD_ZONE from act-gravity.ts.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/home/scroll-story/act-gravity.test.ts` around lines 30 - 35,
The dead-zone test is hardcoding a value that should stay in sync with the
source constant. Export DEAD_ZONE from act-gravity.ts, then update
act-gravity.test.ts to reference that symbol instead of using the unexported
magic number in the plateau assertion. Keep the test aligned with nearestHold
and ACT_HOLDS so future changes to the dead zone only need one update.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/home/scroll-story/act-gravity.test.ts`:
- Around line 72-94: The current useActGravity coverage only checks debounce
cancellation, so add tests that exercise the actual settle behavior in
GravityHarness/useActGravity by stubbing window.scrollTo and
Element.prototype.getBoundingClientRect and asserting a hold selection triggers
the “pull toward plateau” path when scrolling stops; also add coverage for the
scrollend-supported branch and the prefers-reduced-motion early return so the
main behavior and skip paths are both verified.
- Around line 30-35: The dead-zone test is hardcoding a value that should stay
in sync with the source constant. Export DEAD_ZONE from act-gravity.ts, then
update act-gravity.test.ts to reference that symbol instead of using the
unexported magic number in the plateau assertion. Keep the test aligned with
nearestHold and ACT_HOLDS so future changes to the dead zone only need one
update.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6c48e6b4-20dc-485c-a3d7-33f571f18a85

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7c2c9 and 5f9ecae.

📒 Files selected for processing (4)
  • src/components/home/scroll-story/act-gravity.test.ts
  • src/components/home/scroll-story/act-gravity.ts
  • src/components/home/scroll-story/scroll-story.test.tsx
  • src/components/home/scroll-story/scroll-story.tsx

@greptile-apps greptile-apps 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.

kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🚀 Preview: https://wcpos-1zhqqdxzv-wcpos.vercel.app

@wcpos-bot

wcpos-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Fixed the current actionable CodeRabbit review-body feedback in commit db770a4.

Thread File Issue Decision Commit
CodeRabbit review 4619661993 / cr-comment:e70ba1146dbb2e7a4abc6277 act-gravity.test.ts Dead-zone assertion used a hardcoded value instead of the source constant. Fixed: exported DEAD_ZONE and updated the assertion to use DEAD_ZONE / 2. db770a4
CodeRabbit review 4619661993 / cr-comment:64775eabeaa4855271ffb1ee act-gravity.test.ts useActGravity coverage only checked cancellation, not actual settle behavior, the scrollend path, or reduced-motion early return. Fixed: added focused hook tests for fallback settle, scrollend settle, and reduced-motion skip behavior. db770a4

Skipped threads: none; fresh unresolved inline review-thread inventory returned 0 rows.

Validation:

  • pnpm install --frozen-lockfile: passed.
  • pnpm lint: passed with 5 existing warnings outside this change.
  • pnpm exec tsc --noEmit: passed.
  • pnpm vitest run src/components/home/scroll-story/act-gravity.test.ts: passed, 1 file / 8 tests.
  • pnpm test:unit: passed, 139 files / 963 tests.
  • Local pnpm test:e2e --project=chromium: failed because local Chromium cannot load libglib-2.0.so.0; GitHub Actions E2E passed on commit db770a4.

Post-push status: merge state is clean, remote Test/E2E/CodeQL/Deploy Preview checks are passing, CodeRabbit status is success, and remaining unresolved inline review threads after final GraphQL inventory: 0.

@kilbot kilbot merged commit 1eeee05 into main Jul 2, 2026
9 checks passed
@kilbot kilbot deleted the scroll-story-act-gravity branch July 2, 2026 17:28
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.

1 participant