feat(onboarding): Add a guided onboarding tour for newcomers - #90
Open
cn0303 wants to merge 10 commits into
Open
feat(onboarding): Add a guided onboarding tour for newcomers#90cn0303 wants to merge 10 commits into
cn0303 wants to merge 10 commits into
Conversation
New users land in front of the full LeRobot pipeline at once, with no guide through calibrate, record, train, and run. There was no onboarding surface beyond the install modal. Add a self-contained guided tour built on the Radix/shadcn primitives already in the tree, so it pulls in no new dependencies. A step model describes each stage in plain language and names the real element to highlight via a data-tour attribute; a spotlight overlay dims the page, cuts a hole over the target, tracks it across scroll and resize, and positions a tour card beside it. An OnboardingProvider drives the linear step machine and persists a seen flag, and a reusable launcher button starts the tour from the landing top bar or a floating corner control on any page. This is the first, hardware-independent layer: the walkthrough runs and is drivable end to end. Cross-page navigation, state awareness, the first-visit welcome, and motion polish build on top in later commits.
The engine only showed steps on whatever page happened to be open, so a step describing calibration or recording had nothing to point at unless the user was already there. Drive navigation from the step model: when a step is entered, route to the page it lives on so its target can mount and be highlighted. The calibration page needs the selected robot in navigation state to render that robot's controls, so forward the persisted selection when heading there. Navigation fires once per step entry rather than on every location change, so a user who clicks elsewhere mid-step is not dragged back.
A fixed click-through can't tell whether the user actually calibrated, recorded, or trained, so it either nags people who are already ahead or races ahead of people who aren't. Read a live progress snapshot from the endpoints the app already exposes (robots, datasets, jobs, auth) and use it to drive the walkthrough. The snapshot only polls while the tour is open, so it costs nothing when closed and deliberately avoids a second useRobots instance. Steps carry optional predicates: gate marks an action whose prerequisite isn't met yet and surfaces a hint, isComplete marks it done and gently auto-advances on the transition, and show hides steps that don't apply (for example, the Hub step for someone already signed in). The current step is always kept visible so a changing snapshot can never strand the tour mid-view.
Until now the tour only started if someone found the launcher, so most newcomers would never see it. Show a short welcome dialog on the first visit, styled like the existing install modal, offering the tour or a quiet dismissal. The choice is remembered so it never nags on return. On the hosted Space the offer is suppressed, since the non-dismissible install prompt already owns that first-run moment and the two must not stack; the corner launcher remains available everywhere so the tour can always be replayed.
Round off the interaction so it feels considered rather than mechanical. Each step's card fades and scales in, honouring reduced-motion preferences, and remounts per step so the entrance replays. Focus moves to the card when a step opens and the card announces politely, so keyboard and screen-reader users follow along; Escape already exits from anywhere.
While the tour was open the progress snapshot polled /jobs/hub every two seconds, and each call reaches the Hugging Face Hub (list_jobs plus list_models). Over a couple of minutes that is dozens of Hub requests, which runs against the care this project already takes to avoid Hub rate limits. Drop /jobs/hub entirely. Tracked cloud jobs already appear in the local /jobs list, so a trained model is still detected there, and the only thing lost is untracked past Hub models, which the tour does not need. Authentication now comes from the existing HfAuth context rather than the hub response. The poll also eases to three seconds, pauses while the tab is hidden, and guards against overlapping requests, so nothing piles up.
The previous commit stopped the tour polling /jobs/hub, but its progress snapshot still called /datasets every few seconds, and that endpoint merges in the user's Hub datasets (list_user_datasets -> api.list_datasets) for authenticated users. So the tour still issued a Hub request on every poll, undercutting the earlier fix. Give /datasets a `scope=local` mode that returns only the local-cache listing — a pure filesystem scan, no Hub call — and point the tour poll at it. Tracked cloud datasets aren't needed to answer "has the user recorded anything on this machine yet." The default scope is unchanged, so existing callers keep the merged listing. Adds coverage for both the new helper and the endpoint branch, asserting the local path never reaches the Hub.
A step whose target sits below the fold (the cameras step on the calibration page, the jobs step on a busy landing page) was highlighted where it actually is — off-screen — leaving the tour card pointing at nothing the user could see. When a target is found, scroll it into view with block "nearest", which moves the minimum needed and does nothing when the element is already visible. The existing scroll listener keeps the cutout and card glued to it as the smooth scroll settles.
The hint on a locked step told the user they could move on with Skip, but Skip only renders for optional steps. The gated steps that most need the hint (record, train) are required, so they show no Skip button — only Next, which always advances. Point the hint at Next, which is present on every step, so the guidance matches the buttons actually on screen.
The tour deliberately does not re-navigate when the user clicks away mid-step, expecting the spotlight to fall back to a centered card. But the overlay only re-tracked on step or target changes, not on route changes, so after a manual navigation it kept rendering the last-measured rect — a highlight pinned over wherever the element used to be on the new page. Re-run the tracking effect on route changes so it re-queries the target (and falls back to centered when it isn't on the new page), and drop the rect if the tracked element leaves the DOM under us, rather than pinning it to a stale position.
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.
What this adds
A guided, interactive onboarding tour that walks a first-time user through the whole LeRobot loop
inside LeLab. From picking a robot, calibrating it, recording a dataset, training a policy to running it.
All in plain language, without them having to know the jargon or hunt for where each step lives.
Following up on our conversation about lowering the barrier for newcomers (students, hackathon
first-timers, anyone unboxing an SO-101), this is the first, self-contained piece: a real product
tour of the existing UI. It's built so a chat-style "collection assistant" can grow out of it later,
but that is deliberately out of scope here so this PR stays focused and reviewable.
Demo
onboarding-tour-demo-1080p.mp4
What the user sees
dismissal). The choice is remembered, so it never nags on return.
the robot selector, the calibrate button, the dataset card, the training button, the jobs list etc.
with a short, jargon-free explanation beside it. The highlighted control stays clickable.
a dataset has been recorded, and a model trained, then marks steps done and gently moves on. Steps
that need hardware are optional and always skippable, so someone browsing without an arm connected
can still complete the whole tour.
?launcher in the landing top bar and a floating button onevery page.
How it works
primitives already in the tree.
frontend/distis left untouched (it is rebuilt from source bybuild_frontend.ymlon merge). The only backend change is a small, additivescope=localmode onthe existing
/datasetsendpoint (a pure filesystem scan, no Hub call), with test coverage — seebelow.
and the tour polls only cheap local ones while it's open (zero cost when closed):
/robots(
is_clean),/datasets?scope=local, and/jobs. It deliberately avoids/jobs/huband theHub-merging default of
/datasets; tracked cloud jobs already surface in/jobs, and auth comesfrom the existing HfAuth context. The poll pauses while the tab is hidden.
install modal already owns the first-run moment, so the two never stack.
lib/onboardingSteps.ts) names the real element tohighlight via a
data-tourattribute; anOnboardingProviderdrives the step machine, navigation,and persistence; a
SpotlightOverlaytracks the target across scroll/resize and routes; aTourCardpositions the guidance with viewport-aware flipping. Accessible: focus moves to the card,it announces politely, and Escape exits from anywhere.
The change is organised as small, self-contained commits, each of which type-checks on its own:
engine → cross-page navigation → progress-awareness → first-visit welcome → motion/accessibility
polish, followed by review-driven fixes (keeping the progress poll and dataset check off the Hub,
scrolling below-the-fold targets into view, and a hint correction).
Try it locally
Open
http://localhost:8080. To see the first-run welcome again after dismissing it, clear the flagin the browser console and reload:
Testing
The backend change ships with
pytestcoverage (tests/test_datasets.py,tests/test_server.py):the new local-only listing is tested for its
source="local"tagging and, at the endpoint level, fornever reaching the Hub on
scope=local. The full suite passes.There is no frontend test harness in the repo, so the UI was verified with
tsc --noEmit, ESLint,npm run build, and a manual walkthrough vialelab --dev: first-run offer, per-step spotlight andnavigation (including scrolling below-the-fold targets into view), progress-driven auto-advance, the
skip/escape paths for hardware-free browsing, replay from both launchers, and behaviour under
resize/scroll. The UI is browser code with no OS-specific paths, so it behaves the same on Windows,
Linux, and macOS.