Skip to content

feat(landing): full-page scroll-reactive 3D background, mobile fixes & snapshot tests#64

Merged
hoangsonww merged 4 commits into
masterfrom
feat/landing-fullpage-3d-and-snapshots
Jun 11, 2026
Merged

feat(landing): full-page scroll-reactive 3D background, mobile fixes & snapshot tests#64
hoangsonww merged 4 commits into
masterfrom
feat/landing-fullpage-3d-and-snapshots

Conversation

@hoangsonww

Copy link
Copy Markdown
Owner

Summary

Builds on the recent cinematic 3D landing overhaul. The 3D background is now a single, continuous, scroll-reactive scene spanning the whole page (it was previously boxed into just the hero and CTA), plus mobile responsiveness fixes and a new Jest snapshot suite.

Landing page

  • One full-page 3D scene — replaced the two isolated hero/CTA canvases with a single persistent position: sticky canvas pinned to the viewport for the entire scroll. Its camera dollies down through a vertical column of frosted-glass panels as you scroll, framing a glowing core at both the hero (top) and CTA (bottom). Scroll progress is held in a ref and read in the render loop, so scrolling never triggers React re-renders.
  • Cohesive dark theme, solid panels — the page floats over the 3D, but content surfaces (cards, stat band, spotlight, testimonial, accordions, marquee chips) are solid/opaque dark panels so copy stays crisp. The 3D shows through the open areas (hero, CTA, section gaps) — not through the cards.
  • Mobile fixes — removed the floating scroll-cue arrow that overlapped the "4 big numbers" stats card; the stats band no longer collides with the hero on small screens.
  • Hero CTA rowTake the tour gains a PlayCircleOutline icon; a new Scroll to explore text button (bouncing ArrowDownward) replaces the old floating arrow and scrolls to the content below.
  • Honors prefers-reduced-motion and keeps the existing WebGL / low-power fallbacks.

Testing

  • New snapshot suite (07_snapshots.test.js, 11 snapshots): chrome (Navbar/Footer/Spinner), static pages (NotFound/Privacy/Terms/HowToUse), auth pages (Login/Register/ForgotPassword), and the redesigned LandingPage. The WebGL hero and WebAuthn helpers are mocked for determinism; heavy runtime-only modals are intentionally excluded.
  • Added jsdom polyfills (matchMedia, Intersection/Resize observers, scroll helpers) to setupTests.js and a renderWithRouter helper.

Results: production build compiles cleanly · 46/46 tests pass · 11/11 snapshots (stable across re-runs).

Notes

  • Only frontend/ touched; backend/orchestrator untouched.
  • Update snapshots after intentional UI changes with npx jest -u.

🤖 Generated with Claude Code

… + snapshot tests

Landing page overhaul:
- Replace the two isolated hero/CTA canvases with ONE persistent full-page
  3D scene (position: sticky) whose camera dollies down through a vertical
  column of frosted-glass panels as the page scrolls, framing a glowing core
  at both the hero (top) and CTA (bottom). Driven by a scroll-progress ref so
  scrolling never re-renders React.
- Cohesive dark theme: content surfaces are now SOLID dark panels (opaque,
  not see-through) so cards/accordions stay crisp, while the 3D shows through
  the open areas (hero, CTA, section gaps).
- Mobile: remove the floating scroll-cue arrow that collided with the stats
  card; the stats band no longer overlaps the hero on small screens.
- Hero CTA row: "Take the tour" gains a PlayCircleOutline icon and a new
  "Scroll to explore" text button (bouncing ArrowDownward) replaces the arrow.
- Honors prefers-reduced-motion and keeps the WebGL/low-power fallbacks.

Testing:
- Add comprehensive Jest snapshot coverage (11 snapshots) for the chrome,
  static pages, auth pages, and the redesigned LandingPage (WebGL hero and
  WebAuthn helpers mocked for determinism).
- Add jsdom polyfills (matchMedia, Intersection/Resize observers, scroll
  helpers) in setupTests and a renderWithRouter test helper.

All 46 tests / 11 snapshots pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 11, 2026 19:17
@netlify

netlify Bot commented Jun 11, 2026

Copy link
Copy Markdown

Deploy Preview for docuthinker-ai-app canceled.

Name Link
🔨 Latest commit f934448
🔍 Latest deploy log https://app.netlify.com/projects/docuthinker-ai-app/deploys/6a2b3dd85a94710008a3c852

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docuthinker-fullstack-app Ignored Ignored Jun 11, 2026 10:59pm

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request implements a dark, cinematic full-page sticky 3D background on the landing page that dynamically responds to scroll progress. It also introduces snapshot tests for various pages and components, along with necessary jsdom polyfills and test utilities. The code review feedback suggests simplifying the scroll reference check using optional chaining and nullish coalescing, replacing dynamic array index keys with stable floatSeed keys for panels and accents to prevent rendering issues, and replacing a hardcoded color with a theme palette token.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +244 to +250
const p = reduceMotion
? 0
: THREE.MathUtils.clamp(
scrollRef && scrollRef.current ? scrollRef.current : 0,
0,
1,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The ternary and logical expression used to safely access scrollRef.current can be simplified and made more idiomatic using modern JavaScript optional chaining (?.) and nullish coalescing (??). This improves readability and maintainability.

    const p = reduceMotion
      ? 0
      : THREE.MathUtils.clamp(scrollRef?.current ?? 0, 0, 1);

Comment on lines 318 to 320
{panels.map((p, i) => (
<Panel key={i} reduceMotion={reduceMotion} lowPower={lowPower} {...p} />
))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using the array index i as a key is an anti-pattern here because the panels list is dynamically filtered based on the lowPower prop. When lowPower is active, the list is filtered, shifting the indices of the remaining elements. This causes React to mismatch component instances, leading to unnecessary re-renders and potential visual jumps in the floating animations.

Since each panel has a unique and stable floatSeed value, we can use it as a stable key instead.

Suggested change
{panels.map((p, i) => (
<Panel key={i} reduceMotion={reduceMotion} lowPower={lowPower} {...p} />
))}
{panels.map((p) => (
<Panel key={p.floatSeed} reduceMotion={reduceMotion} lowPower={lowPower} {...p} />
))}

Comment on lines +322 to +324
{accents.map((a, i) => (
<Accent key={i} reduceMotion={reduceMotion} {...a} />
))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to the panels list, using the array index i as a key for accents causes issues when the list is filtered under lowPower mode.

Using the unique and stable floatSeed property as the key ensures React correctly identifies and preserves the state of each Accent component.

Suggested change
{accents.map((a, i) => (
<Accent key={i} reduceMotion={reduceMotion} {...a} />
))}
{accents.map((a) => (
<Accent key={a.floatSeed} reduceMotion={reduceMotion} {...a} />
))}

p: { xs: 3, md: 6 },
borderRadius: "28px",
backgroundColor: palette.heroBg,
backgroundColor: "#0f0a05",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Avoid using hardcoded color values like "#0f0a05" directly in the component styling. Instead, use a theme palette token (such as palette.surfaceMuted or palette.background) to maintain visual consistency and ensure that any future theme updates propagate correctly.

Suggested change
backgroundColor: "#0f0a05",
backgroundColor: palette.surfaceMuted,

Captured at laptop viewport (1512×834 @2x = 3024×1668) to match the
existing asset, showing the full-page 3D hero and the new CTA row
(Start for free · Take the tour · Scroll to explore).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hoangsonww hoangsonww self-assigned this Jun 11, 2026
@hoangsonww hoangsonww added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request good first issue Good for newcomers labels Jun 11, 2026
hoangsonww and others added 2 commits June 11, 2026 15:55
- README: add Three.js (logo: threedotjs) and React Three Fiber (logo:
  reactos) tech badges; list Three.js / R3F / Drei in the frontend stack;
  describe the scroll-reactive 3D landing experience under the screenshot.
- ARCHITECTURE: new "Landing Page 3D Experience" section (+ TOC entry)
  covering the sticky-canvas/negative-margin compositing, scroll-driven
  camera, procedural scene, capability detection/fallbacks, and how the
  snapshot suite mocks WebGL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hoangsonww
hoangsonww merged commit d2df039 into master Jun 11, 2026
13 checks passed
@hoangsonww hoangsonww added this to the v2.x.x - Enhanced Release milestone Jun 12, 2026
hoangsonww added a commit that referenced this pull request Jun 13, 2026
Resolve conflict in frontend/src/setupTests.js: keep master's jsdom polyfill
block (matchMedia, scrollTo, scrollIntoView, Intersection/Resize observers)
and append the autoFocus neutralization the snapshot suite needs.

master's PR #64 already added snapshot coverage for the static pages, auth
pages, app chrome, and the redesigned 3D LandingPage (07_snapshots.test.js).
To avoid duplicating it, this branch now only keeps snapshot suites for the
data-heavy pages #64 deliberately excluded — Home, Documents, Profile, and
Passkeys — which render their deterministic initial/loading state. The
overlapping per-screen files and the redundant inline-Babel jest.config
change are dropped (a babel.config.js from #64 already transforms JSX).

Docs updated to describe both snapshot suites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request good first issue Good for newcomers

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

2 participants