Redesign the first-run onboarding flow as a branded, animated experience#701
Merged
Conversation
…experience Onboarding was functionally solid but visually flat: identical gray cards on every step, none of the brand blue from the app icon, no motion, and a window that changed size in both dimensions on almost every step. - New OnboardingStyle design system: brand-blue backdrop wash, tinted gradient icon tiles, unified card chrome, one-shot staggered reveals, progress pips - Welcome hero: a self-playing ghost-text demo (type, ghost, Tab, accept) staged in a mock app window, so the product sells itself before the flow asks for permissions; feature chips state the on-device/open-source promise - Steps slide horizontally like Setup Assistant pages; the window keeps one 640pt width and only morphs vertically - Permission cards get per-permission tinted tiles, a springing Done state, and a privacy footnote at the moment of the ask - The gated writing-style screen folds into a single personalize step (Make it yours), so the counted flow is always 4 steps - Keys step renders bindings as physical keycaps with a self-pressing hero key; recording, reset, and clear flows are unchanged - Done step: green seal, a menu-bar discovery callout (the one thing users must remember), the existing feature showcase, and the model status - WelcomeStep extracted to Support/ as a pure, tested enum; the resume key moves to cotabbyOnboardingProgressStep2 because step indices changed - Permission reminder window restyled with the same system, keeping its orange required-and-missing urgency semantics
Greptile P2 on #701: the reminder window hardcoded the required-permission count in its stagger indices while WelcomePermissionStepView derives them; derive both surfaces the same way so adding a permission cannot desync the choreography.
78542a7 to
f45ab16
Compare
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.
Summary
Onboarding is the product's first impression, and it read as a stack of identical gray material cards: no brand color (the app icon's #007AFF appeared nowhere in the flow), no motion, nothing showing what Cotabby actually does until the very last screen, and a window that changed both width and height on almost every step. This PR rebuilds the flow as one designed surface: a shared design system (
OnboardingStyle: brand-blue backdrop wash, tinted gradient icon tiles, unified card chrome, one-shot staggered reveals, refined progress pips), a welcome hero that plays the core loop (type, ghost text appears, Tab accepts) inside a mock app window before the flow asks for anything, Setup Assistant-style slide transitions with a constant 640pt window width, physical keycap rendering on the keys step, and a celebratory finish that leads with menu bar discovery. Structurally, the gated writing-style screen folds into a single "Make it yours" step (name, languages, and, whenCustomRulesCatalog.isUserFacingEnabled, rules), so the counted flow is always 4 steps.WelcomeStepmoves toSupport/as a pure, tested enum, and the permission reminder window adopts the same system while keeping its orange required-and-missing urgency.Validation
Skip notes:
FoundationModelDriftEvalTestsis the same exclusion CI uses.ScreenshotContextGeneratorTestswas skipped locally only because the machine was screen-locked during the run, which blocks that class's window-capture path indefinitely (verified by sampling the stalled process; the stall predates this diff and the class does not touch onboarding). It runs normally on CI.Visual verification: all six steps were rendered off-screen via an
NSHostingViewharness at each step's exact window size, in light and dark appearance (12 PNGs reviewed; saved locally, happy to attach). Confirmed: backdrop wash and icon tiles in both appearances, hero demo mid-ghost with Tab keycap and blinking caret, permission tiles and optional capsule, engine selection stroke and Recommended badge, personalize cards with language suggestions, keycap chrome, done-step seal, menu bar callout, and the live feature showcase. One artifact to know about: prominent buttons render in their gray inactive style in the off-screen captures because a borderless harness window never reports active; in the running app the onboarding window is key and they render brand blue.Linked issues
None. No open issue tracks onboarding visuals; this is a proactive design pass.
Risk / rollout notes
cotabbyOnboardingProgressSteptocotabbyOnboardingProgressStep2because folding the writing-style step shiftedWelcomeStepraw indices. Reading old indices would resume users onto the wrong step, so the old key is deliberately abandoned: anyone caught mid-onboarding across this update restarts at the welcome step. Users who completed onboarding are untouched.currentOnboardingVersionstays at 2 since the redesign gives completed users nothing new to do. If we want everyone to experience the new flow once, bumping it to 3 is a one-line change inWelcomeCoordinator.OnboardingFeatureShowcase(also embedded in Settings Home) is untouched.WelcomeButton/WelcomeNavigationmoved intoOnboardingStyle.swiftwith the same API.Greptile Summary
This PR rebuilds the first-run onboarding wizard from the ground up: a shared
OnboardingStyledesign system (brand-blue backdrop, gradient icon tiles, card chrome, one-shot staggered reveals), a live ghost-text hero demo on the welcome screen, Setup-Assistant-style horizontal slide transitions at a fixed 640 pt window width, physical keycap rendering for the shortcuts step, and a celebratory done step. Structurally, the separate writing-style screen is folded into a single "Make it yours" step, keeping the counted flow at four steps regardless of theCustomRulesCatalogflag.WelcomeStepis extracted toSupport/as a pure, tested enum whose raw values are the persisted resume index; the progress key is versioned tocotabbyOnboardingProgressStep2so users caught mid-flow across this update safely restart at welcome rather than landing on the wrong step.WelcomeCoordinatorpre-sizes the window for the actual resume step (eliminating the initial-frame flash) andPermissionReminderViewadopts the same design system with dynamic stagger indices, fixing the hardcoded-offset issue raised in the previous review.OnboardingFlowStepTestspins the persisted numbering scheme and the constant-width invariant as regression guards for the persistence contract.Confidence Score: 5/5
Safe to merge — this is a presentation-layer rebuild; all underlying logic (template application, model download, permission gating, keybind recording, resume-point persistence) is unchanged or correctly adapted.
The flow model is extracted into a tested pure enum, the persistence key is correctly versioned so no user lands on the wrong step, and the PermissionReminderView now uses dynamic stagger indices. The only issues found are two latent defensive-programming gaps (a ClosedRange crash if OnboardingProgressPips is ever called with total=0, and a matching crash if WelcomeHeroDemo's examples array ever gains an empty base string), neither of which is reachable with the current code.
No files require special attention. WelcomeHeroDemo.swift has the latent range-crash noted above, but it is not exploitable with the current hardcoded examples.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Launch] --> B{isOnboardingCompleted?} B -- No --> C[showWelcome\nresume from cotabbyOnboardingProgressStep2] B -- Yes --> D{requiredPermissionsGranted?} D -- No --> E[showPermissionReminder\nPermissionReminderView] D -- Yes --> F[Normal app launch] C --> W[WelcomeView] W --> S0[welcome\nHeroDemo · no pips] S0 -->|Get Started| S1[permissions\npip 1 of 4] S1 -->|Back| S0 S1 -->|Continue\nrequiredGranted| S2[template\npip 2 of 4] S2 -->|Back| S1 S2 -->|Continue / Set up later| S3[personalize\npip 3 of 4] S3 -->|Back| S2 S3 -->|Continue\n≥1 language| S4[keybind\npip 4 of 4] S4 -->|Back| S3 S4 -->|Continue| S5[done\nno pips] S5 -->|Start Using Cotabby\nonDismiss| G[completeOnboarding\nstamp version · clear resume key] G --> F style S0 fill:#e8f4ff,stroke:#007AFF style S5 fill:#e8ffe8,stroke:#34C759Reviews (2): Last reviewed commit: "fix(onboarding): derive reminder reveal ..." | Re-trigger Greptile