Repository navigation
feat: replace the home experience carousel with a scroll-driven timeline - #93
Merged
Merged
Conversation
The home page's 3D carousel becomes a horizontal timeline: one node per role,
present to past left to right, panning sideways as the page scrolls down. The
component itself is refract-ui's new ScrollTimeline (1.1.0); this is the wiring
plus the data correction it surfaced.
Six nodes instead of three slides, since the argument the timeline makes is that
the roles are a sequence — collapsing three Walmart years into one node would
flatten the part worth showing. Models are windowed to the active node and its
neighbours, so three WebGL contexts stay live rather than six.
data/experience: Intuit's roles were ordered oldest-first while Company.roles is
documented newest-first, and the home carousel read roles[0] — so the page has
been rendering the older role's title welded to the current date range ('Staff
Software Engineer, Intuit Design System - Jul 2022 - Present'). Reordered
newest-first, which fixes that. Titles and highlights stay with their teams:
Staff was Intuit Design System, Senior is the current Identity role.
Home: #experience can no longer be one snapport tall, so it takes a runway and
opts out of scroll-snap-stop. activeSection moves from scrollTop / clientHeight
to an offsetTop lookup, since that division assumed every section was exactly
one viewport and would have reported four panes while inside the third.
Home.module.css: .home is now positioned. That is required, not cosmetic —
scroll progress is measured by walking offsetParent up from the timeline to the
container, and a static container is never in that chain, so progress pins at 0
and the timeline renders without ever moving.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parammehta
force-pushed
the
feat/experience-timeline
branch
from
August 26, 2026 01:42
6ed499f to
5786b41
Compare
Cards alternate sides by index, which carries no meaning on its own. Starting above put the Senior Identity role over the Staff role directly beside it — two adjacent titles at the same company, which reads as a ranking whether or not one is meant. Starting below fixes that pair and improves the rest: Staff now sits above both Seniors adjacent to it, Walmart's Senior sits above the engineer role beside it, and the same-level pairs imply nothing either way. Needs refract-ui 1.2.0 for the startSide prop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The home page's 3D carousel becomes a horizontal timeline: one node per role, present to past left to right, panning sideways as the page scrolls down. Inspired by interfaces.kylejeong.com.
The component is refract-ui's new
ScrollTimeline(refract-ui#7, released as 1.1.0). This PR is the wiring, plus the data correction it surfaced.Six nodes, not three slides
One node per role rather than per company. The argument a timeline makes is that the roles are a sequence, and collapsing three Walmart years into one node would flatten the part worth showing:
Nothing sorts at render time —
companiesis newest-first and each company'srolesare too, so a flat map already reads present to past. If the order ever looks wrong, the data is what's wrong.The device models are kept, but windowed to the active node and its immediate neighbours.
Modelbuilds aWebGLRendererper instance and browsers cap live contexts; mounting all six would sit near that ceiling for the whole page, on a landing page that also runs the hero sphere. Verified in the browser: 3 canvases live at any time, not 6.A data bug this surfaced
Company.rolesis documented "Newest role first", but Intuit's array was oldest-first — and the carousel readcompany.roles[0].titlealongside the company's date range. So the live page has been rendering the older role's title welded to the current dates: "Staff Software Engineer, Intuit Design System · Jul 2022 – Present".Fixed by reordering newest-first. Titles and highlights stay with their teams — Staff was the Design System role, Senior is the current Identity role. This also corrects
/experience, which rendersroles[0]as the lead heading.Home page: the snap deck had to give a little
.homeis ascroll-snap-type: y mandatorydeck where every section is exactly one snapport tall. The timeline needs the opposite — a section several viewports tall with a sticky child — so#experiencenow carriesdata-runway, which releases theheight: 100%and dropsscroll-snap-stop: alwaysfor that pane only. It still snaps at its top edge.That broke
activeSection = Math.round(scrollTop / clientHeight), which hard-assumed uniform pane heights and would have reported sections 2–5 while you were still inside the third. Replaced with anoffsetToplookup over the section refs — more correct regardless..homeis nowposition: relative, and that is load-bearing. framer-motion measures scroll progress inside a custom container by walkingoffsetParentup from the target until it reaches the container. A static container is never in that chain, so the walk runs off the top of the document and progress pins at 0 — the timeline renders perfectly and never moves. It's commented in place so it doesn't get "cleaned up" later.Smaller notes
z: 10.4to7.8— a timeline card is far wider than it is tall and the vertical FOV is fixed, so the carousel's framing left the devices small in a lot of empty width.home_experience_slidekeeps its name and now fires on active-node change, so the Worker'sALLOWED_EVENTSallowlist needs no change.storybookentry from.claude/launch.jsonpointing at a binary that no longer exists here (Storybook lives in refract-ui now).Testing
npm run preflightpasses against the published refract-ui 1.1.0 — lint, stylelint, typecheck, 36 unit, 24 integration, worker tests, build, 37 e2e.Three new integration tests: every role appears in
data/experienceorder (derived from the data, so adding a role can't leave the test asserting a stale list), the CTA points at the active role's company, and#experiencecarries its runway attribute.Verified in a real browser on desktop and mobile — full traversal in both directions with actual wheel input, sticky viewport holding, every node centring at rest, no collisions between cards and the pinned heading/CTA or the fixed navbar.
🤖 Generated with Claude Code