108 lines
4.8 KiB
Markdown
108 lines
4.8 KiB
Markdown
Status
|
||
|
||
Draft
|
||
|
||
Story
|
||
|
||
**As a** storyteller,
|
||
**I want** a sticky split component,
|
||
**so that** narrative and media synchronize during scroll.
|
||
|
||
Acceptance Criteria
|
||
|
||
1. <StickySplit.Section/Sticky/Track/Panel> components implemented with docs.
|
||
2. Reduced‑motion mode disables heavy animations gracefully.
|
||
3. Mobile layout stacks content; performance budget respected.
|
||
|
||
Tasks / Subtasks
|
||
|
||
- [ ] Scaffold pattern components (AC: 1)
|
||
- [ ] Create folder `src/components/patterns/sticky-split/`
|
||
- [ ] Add files: `Section.tsx`, `Sticky.tsx`, `Track.tsx`, `Panel.tsx`, `index.ts`
|
||
- [ ] Export namespaced API: `StickySplit = { Section, Sticky, Track, Panel }`
|
||
- [ ] Define props:
|
||
- Section: `{ id: string; height?: string | number; side?: 'left'|'right'; className?: string }`
|
||
- Sticky: `{ offset?: string; className?: string }`
|
||
- Track: `{ className?: string }`
|
||
- Panel: `{ index: number; inVariants?: Variants; outVariants?: Variants; className?: string }`
|
||
- [ ] Provide sensible defaults: `height='200vh'`, `side='left'`, sticky `offset='var(--sticky-top, 8vh)'`
|
||
- [ ] Progress computation (AC: 1)
|
||
- [ ] Implement `useSectionProgress(id)` in `src/components/patterns/sticky-split/useSectionProgress.ts`
|
||
- [ ] Use `IntersectionObserver` on Section root to compute 0..1 progress across its scroll range
|
||
- [ ] Ensure passive listeners only; no wheel/touch blocking; avoid scroll‑jacking
|
||
- [ ] Animation integration (AC: 1)
|
||
- [ ] Use `framer-motion` `motion.div` inside `Panel` and map `progress` to opacity/transform via `useTransform`
|
||
- [ ] Add optional `inVariants/outVariants` props; default to subtle fade/scale
|
||
- [ ] Reduced motion (AC: 2)
|
||
- [ ] Use `useReducedMotion()` from framer‑motion; if true, disable transforms and show panels as static stack
|
||
- [ ] Mobile layout + fallbacks (AC: 3)
|
||
- [ ] Apply responsive CSS: below `md`, stack vertically; disable sticky; panels visible with light reveal‑on‑view (IO add/remove `is-visible` class)
|
||
- [ ] Above `md`, two‑column grid with left sticky narrative and right scroll track; allow `side='right'` to invert
|
||
- [ ] Tokens and base styles (AC: 1,3)
|
||
- [ ] Define CSS vars in `src/app/globals.css`: `--sticky-top`, `--panel-gap`, `--reveal-duration`, `--reveal-ease`
|
||
- [ ] Provide utility classes for the pattern container grid and gaps using Tailwind + CSS vars
|
||
- [ ] Documentation & example (AC: 1)
|
||
- [ ] Add `src/components/patterns/sticky-split/README.md` with usage, props, and examples
|
||
- [ ] Include a small demo component `Demo.tsx` showcasing 3 panels; do not add a new route in this story
|
||
- [ ] Quality gates & perf
|
||
- [ ] Lint passes: `npm run lint`
|
||
- [ ] Build passes: `npm run build`
|
||
- [ ] Verify no main thread jank on mid‑range device; keep frame budget ≈16ms for panel transitions
|
||
- [ ] Confirm passive listeners; no prevention of native scroll
|
||
|
||
Dev Notes
|
||
|
||
- Context
|
||
- Derived from PRD Story 1.3. Target: reusable pattern inspired by “Basement Foundry” style; no scroll‑jacking.
|
||
- Typography and tokens are handled in Story 1.1; this story may add a few CSS vars specific to the pattern.
|
||
- Relevant Source Tree
|
||
- Component home: `src/components/patterns/sticky-split/*`
|
||
- Tailwind/CSS tokens: `src/app/globals.css`, `tailwind.config.ts`
|
||
- Motion libs: `framer-motion`/`motion` available in dependencies.
|
||
- Implementation Guidance
|
||
- Section renders a responsive two‑column grid (`md:grid md:grid-cols-2`) with a fixed sticky column and a scrolling track column; swap order with `side`.
|
||
- Sticky uses `position: sticky; top: var(--sticky-top)` and inherits tokenized spacing/gap via CSS vars.
|
||
- Track holds `Panel` children; each Panel uses the section progress (or per‑panel thresholds like `index / (N-1)`) to compute in/out.
|
||
- Reduced motion: early return static markup; prefer opacity reveals without transforms.
|
||
- Accessibility: preserve DOM order for reading; keep focusable content reachable; avoid trapping focus.
|
||
- Performance: avoid large fixed layers; prefer `will-change: transform` only while animating; lazy‑load media inside panels.
|
||
|
||
Testing
|
||
|
||
- Manual
|
||
- With default motion: panels fade/transform smoothly as the section scrolls; no scroll blocking.
|
||
- With `prefers-reduced-motion`: panels render as static stack; no transforms/animations.
|
||
- Mobile: stacked layout; sticky disabled; content readable and navigable.
|
||
- Perf
|
||
- Inspect Chrome Performance or DevTools frame rate timeline; verify transitions stay near 60fps on typical hardware.
|
||
- A11y
|
||
- Keyboard navigation reaches all interactive elements inside Sticky and Track; focus order logical.
|
||
|
||
Change Log
|
||
|
||
| Date | Version | Description | Author |
|
||
|------|---------|-------------|--------|
|
||
| 2025-09-24 | v1 | Initial draft from PRD Story 1.3 | Scrum Master |
|
||
|
||
Dev Agent Record
|
||
|
||
Agent Model Used
|
||
|
||
{{agent_model_name_version}}
|
||
|
||
Debug Log References
|
||
|
||
|
||
|
||
Completion Notes List
|
||
|
||
|
||
|
||
File List
|
||
|
||
|
||
|
||
QA Results
|
||
|
||
|