Skip to content

docs-site: hero constellation, entrance and scroll motion with accessibility guardrails - #36

Merged
omrsamer merged 1 commit into
mainfrom
feat/docs-site-motion
Sep 29, 2026
Merged

omrsamer merged 1 commit into
mainfrom
feat/docs-site-motion

Conversation

@omrsamer

Copy link
Copy Markdown
Contributor

Summary

Adds motion to the GitHub Pages site (docs-site/) in the spirit of the animated hero on sample-ac-central, built to the constraints this site already follows: no runtime network requests, no external assets, no analytics, WCAG 2.2 AA, zero layout shift. Every effect respects prefers-reduced-motion, the only auto-playing effect has a pause control (WCAG 2.2.2), and a new Playwright spec keeps those promises enforced in CI.

Repository-side change is one file: assets/repository-atlas-journey.svg gains a declarative CSS entrance animation. No project folder changed.

What changed

Phase 1: CSS motion

  • Hero entrance in PageHeader: eyebrow, title, lead, meta, actions and figure ease in with a 60 ms stagger, CSS only, under prefers-reduced-motion: no-preference.
  • Scroll reveal via CSS scroll-driven animations (animation-timeline: view() behind @supports), exposed as a data-reveal attribute. Blocks rise into place but never fade, so text contrast is identical at every scroll position and axe or Lighthouse see the same colours as the reader. Browsers without support show content at rest.
  • Hover lift via data-lift on cards and tiles, only on pointer devices (hover: hover).
  • The Atlas SVG draws itself: hub, then the four project cards, then the shared-capability links, then each journey line draws in with its arrowhead fading in after it. The animation lives in a <style> block inside the SVG so it also runs inside <img>, and it sits entirely behind prefers-reduced-motion: no-preference. Markers were replaced by explicit arrowhead paths so they can fade in after their line.

Phase 2: constellation canvas hero background

  • A vanilla canvas engine (no dependency) draws drifting points and proximity links behind the Home hero, coloured from the site's CSS variables so it follows the theme.
  • Loaded lazily with React.lazy after the page is idle, code-split into its own chunk with a gzip budget enforced by test.
  • Pauses when the hero leaves the viewport, when the tab is hidden, and on a visible "Pause background" button with aria-pressed. Capped at 30 fps and sized with devicePixelRatio clamped.
  • Under reduced motion it renders one static frame and the button reads "Play background", so the user can opt in.
  • The canvas is aria-hidden, positioned absolutely behind the header, and never affects layout (CLS measured 0).

Phase 3: guardrails

  • tests/browser/motion.spec.ts: running state, pause control size and toggling, off-screen pausing, CLS under 0.02, static frame under reduced motion with zero running keyframe animations, chunk size budget and main-bundle exclusion, hero entrance settling, scroll reveal never fading and settling in view, Atlas SVG free of scripts and inert under reduced motion.
  • tests/browser/a11y.spec.ts now waits for time-based animations to finish before running axe, so it audits the settled page rather than a frame of the hero mid-entrance.
  • New unit tests for the constellation engine, renderer and component (16 tests, seeded PRNG).
  • Existing gates unchanged and passing: typecheck, lint, unit tests, build, validate_static.py, audit, full browser suite with axe.

Verification

  • npm run typecheck, npm run lint (zero warnings), npm test (917 tests), npm run build (37 pages prerendered), npm run validate:static, npm run audit (0 vulnerabilities), npm run test:browser (167 passed, 2 viewport-conditional skips, 0 failed) on Node 22 locally.
  • Lighthouse on the built Home page (mobile emulation, local preview): performance 96, accessibility 100, best practices 100, SEO 100; cumulative layout shift 0.
  • Constellation chunk: 6.7 KB raw, about 3 KB gzipped (budget 8 KB). Hero height at 1440 and 390 px is identical to the previous build.
  • Hero screenshots at 1440 and 390 px with the background running show the title, lead and buttons clearly legible; the copy column dims the drawing to 25 percent so text contrast stays comfortably above AA even under a node.
  • No console errors and no off-origin requests while browsing Home with the background running.

Notes

  • Playwright's reducedMotion emulation does not propagate into SVG documents embedded via <img>, so the SVG test loads the file directly. With the browser-level preference (--force-prefers-reduced-motion) the embedded image renders static, which is what real users get.
  • Firefox and Safari without animation-timeline support see content at rest; the reveal is progressive enhancement only.

🤖 Generated with Claude Code

…tlas animation)

Phase 1, CSS motion:
- PageHeader entrance: eyebrow, title, lead, meta, actions and figure ease
  in with a 60 ms stagger, CSS only, under prefers-reduced-motion: no-preference.
- data-reveal: rise-into-place on scroll via CSS scroll-driven animations
  (animation-timeline: view() behind @supports). Moves without fading so text
  contrast is identical at every scroll position.
- data-lift: hover lift with shadow on pointer devices only.
- assets/repository-atlas-journey.svg: declarative entrance animation in an
  SVG <style> block (hub, cards, links, then journey lines drawing in with
  arrowheads fading in after them). Markers replaced by explicit arrowhead
  paths. Everything behind prefers-reduced-motion: no-preference; no script.

Phase 2, constellation hero background:
- Vanilla canvas engine (seeded PRNG, node clamp, distance-faded edges,
  pulses) and renderer, lazy-loaded after idle into a PageHeader backdrop slot
  on Home only. Code-split chunk about 3 KB gzipped.
- Pauses off-screen, when the tab is hidden, and on a visible
  "Pause background" / "Play background" button with aria-pressed
  (WCAG 2.2.2). Static single frame under reduced motion with opt-in play.
- Canvas is aria-hidden, absolutely positioned, zero layout shift. Copy
  column dims the drawing to 25 percent to protect text contrast.

Phase 3, guardrails:
- tests/browser/motion.spec.ts: running/paused/static states, pause control
  size and toggling, off-screen pause, CLS < 0.02, no keyframe animation
  under reduced motion, chunk budget and main-bundle exclusion, entrance
  settling, reveal never fading, Atlas SVG free of scripts and inert under
  reduced motion.
- a11y.spec.ts waits for time-based animations to settle before running axe.
- 16 unit tests for the engine, renderer and component.
- README: hero background animation and other motion sections.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@omrsamer
omrsamer merged commit 638bf1f into main Sep 29, 2026
7 checks passed
@omrsamer
omrsamer deleted the feat/docs-site-motion branch September 29, 2026 11:01
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