Skip to content

feat(docs): build the Extensible card's story - #242

Merged
hunterbecton merged 8 commits into
mainfrom
hunter/sha-214-build-the-extensible-cards-story
Oct 10, 2026
Merged

hunterbecton merged 8 commits into
mainfrom
hunter/sha-214-build-the-extensible-cards-story

Conversation

@hunterbecton

@hunterbecton hunterbecton commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Why

The Extensible feature card showed an image exported from Figma. SHA-214 rebuilds it in code, gives it a story that plays on hover, and builds the hover lifecycle the other three feature cards will reuse.

What changes

The still frame in code

extensible-illustration.tsx draws the mock's code window in the DOM. Every length is a mock pixel scaled to the card's window, which is now a size container, so the drawing scales the way the image did. It follows the mock's geometry, with three exceptions. The code repeats every seven lines, so lines 8 and 9 copy lines 1 and 2. The mock's fade over the bottom edge is gone, because a line typing under it looked odd. Without the fade, the tenth line sat against the bottom edge, so the still frame writes nine lines and leaves the tenth slot empty.

The story

On hover, the code steps up one line at a time. Each step lifts a blank line out of the empty tenth slot, and it types in as the ninth line, its bars growing up from their baseline. Seven steps land back on the still frame after 1.99 seconds. The story keeps playing while the pointer stays. Once the pointer leaves, the play under way finishes. Each play mounts a fresh column of code, so one play hands over to the next without a seam.

The shared lifecycle

story.tsx holds what every feature card's story shares. StoryCard renders the card, and an illustration calls useStory() to learn when to play. useStory() listens to the whole card behind the site's hover gate, ignores touch pointers, and never starts under reduced motion. A hover during a play doesn't restart it. The hero pause and the preload wait for the first card with a live scene.

The hover gate moved from favorites-list.tsx to lib/use-can-hover.ts, and the card tab's --ease-out curve moved to lib/easing.ts, so the favorites and the feature cards share both. SHA-178 records the shared motion rules and the values the author picked.

Feature cards now pick their illustration by id in features.tsx, and content/homepage.ts keeps only their copy. features-extensible.spec.ts covers the hover, the finish after the pointer leaves, no restart, the repeat while the pointer stays, touch, and reduced motion.

Replace the exported Extensible illustration with the code window built in
the DOM, so its story can move the lines (SHA-214). Lengths are in mock
pixels scaled by the card's window, so it scales like the image did. The
code repeats every seven lines, so lines 8 to 10 copy lines 1 to 3 and the
story can scroll seven lines back onto the still frame. Feature cards now
pick their illustration by id, and the content module keeps only copy.
Move the favorites' hover query into lib/use-can-hover.ts, so the feature
cards can play their stories behind the same gate.
Move the card tab's copy of the --ease-out curve into lib/easing.ts, so the
feature cards' stories ease on the same curve without a second copy.
Add the lifecycle every feature card's story shares, in story.tsx. A hover
behind the site's hover gate plays a card's story, and it keeps playing
while the pointer stays. Once the pointer leaves, the play under way
finishes and the card rests on its still frame. A hover during a play
doesn't restart it. Touch pointers and reduced motion leave the card on its
still frame.

The Extensible story steps the code up one line at a time and types each
new line in the ninth slot, where the bottom fade has barely begun: its
bars grow in from their baseline, left to right. The still frame leaves the
tenth slot empty under the fade, so seven steps land back on it. Each play,
and the end of the story, mounts a fresh column at the still frame, so the
swap shows no seam.

features-extensible.spec.ts covers the hover, the finish after the pointer
leaves, no restart, the story continuing while the pointer stays, touch,
and reduced motion.
Copilot AI balanced review requested due to automatic review settings October 10, 2026 11:56
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit da59b1c.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is internally consistent and its interaction and accessibility behavior are thoroughly covered.

0 open findings

What changed in this PR

Rebuilds the Extensible feature-card illustration in code and adds a reusable hover-story lifecycle.

Changes:

  • Adds the animated Extensible code-window illustration.
  • Introduces shared hover detection, easing, and story lifecycle utilities.
  • Adds comprehensive interaction, touch, reduced-motion, and accessibility coverage.
File Description
apps/​docs/​src/​lib/​use-can-hover.ts Adds the shared hover-capability hook.
apps/​docs/​src/​lib/​easing.ts Exports the shared easing curve.
apps/​docs/​src/​content/​homepage.ts Identifies feature cards by typed IDs.
apps/​docs/​src/​components/​features/​story.tsx Implements reusable story-card lifecycle.
apps/​docs/​src/​components/​features/​features.tsx Selects coded or static illustrations by ID.
apps/​docs/​src/​components/​features/​features.module.css Makes illustration windows size containers.
apps/​docs/​src/​components/​features/​extensible-illustration.tsx Implements the animated code-window story.
apps/​docs/​src/​components/​features/​extensible-illustration.module.css Styles and scales the coded illustration.
apps/​docs/​src/​components/​favorites/​favorites-list.tsx Adopts shared hover detection.
apps/​docs/​src/​components/​favorites/​card-tab.tsx Adopts the shared easing token.
apps/​docs-tests/​docs/​homepage.spec.ts Updates feature-illustration assertions.
apps/​docs-tests/​docs/​features-extensible.spec.ts Tests the complete story lifecycle.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

The still frame left the tenth slot empty, so the bottom fade covered plain
black and didn't show. The slot now holds the next line again, faint under
the fade as in the mock. A play starts with that line blank, and the first
step lifts it into the ninth slot to type, as before. The line blanks when a
play starts and returns when the story stops, both under the darkest part of
the fade.
Copilot AI balanced review requested due to automatic review settings October 10, 2026 14:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is internally consistent and its interaction and accessibility behavior are comprehensively covered.

0 open findings

🧠 Review effort: Balanced

During a play the tenth slot was empty, so the bottom fade covered plain
black. The slot now always holds the next line, faint under the fade, as a
hint of the code to come. Each step drops that line flat as it starts to
rise, while the fade still hides most of it, and the line types in once it
lands in the ninth slot. A play now ends exactly on the still frame, so the
start and end of the story no longer blank or restore anything.
Copilot AI balanced review requested due to automatic review settings October 10, 2026 14:24
A line animating under the bottom fade looked odd, so the fade goes, at the
author's call. With nothing to hide the bottom slot, the story types each
new line there, in full view, rather than in the ninth slot, and the still
frame shows all ten lines. A play takes 1.95 seconds.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is coherent, reusable, and comprehensively covered without identified correctness issues.

0 open findings

🧠 Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 10, 2026 14:31
Without the fade, the tenth line sat against the code block's bottom edge.
The still frame writes nine lines again and leaves the tenth slot empty, so
the code stops short of the edge. Each step lifts a blank line out of that
slot, and it types in as the ninth. A play takes 1.99 seconds.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new scroll recorder throws on Motion’s identity transform, preventing the story tests from collecting measurements.

1 open finding

🧠 Review effort: Balanced

Comment thread apps/docs-tests/docs/features-extensible.spec.ts
Copilot AI balanced review requested due to automatic review settings October 10, 2026 14:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation matches the described lifecycle and includes comprehensive interaction coverage.

1 open finding

🧠 Review effort: Balanced

@hunterbecton
hunterbecton merged commit 51da958 into main Oct 10, 2026
12 checks passed
@hunterbecton
hunterbecton deleted the hunter/sha-214-build-the-extensible-cards-story branch October 10, 2026 14:55
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.

2 participants