Skip to content

Redesign the first-run onboarding flow as a branded, animated experience#701

Merged
FuJacob merged 2 commits into
mainfrom
feat/onboarding-redesign
Jun 12, 2026
Merged

Redesign the first-run onboarding flow as a branded, animated experience#701
FuJacob merged 2 commits into
mainfrom
feat/onboarding-redesign

Conversation

@FuJacob

@FuJacob FuJacob commented Jun 12, 2026

Copy link
Copy Markdown
Owner

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, when CustomRulesCatalog.isUserFacingEnabled, rules), so the counted flow is always 4 steps. WelcomeStep moves to Support/ as a pure, tested enum, and the permission reminder window adopts the same system while keeping its orange required-and-missing urgency.

Validation

xcodegen generate
# committed project matches (no drift)

swiftlint lint --quiet --strict
# exit 0

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' \
  -configuration Debug build -derivedDataPath build/DerivedData
# ** BUILD SUCCEEDED **

xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' \
  -derivedDataPath build/DerivedData \
  -skip-testing:CotabbyTests/FoundationModelDriftEvalTests \
  -skip-testing:CotabbyTests/ScreenshotContextGeneratorTests \
  CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
# ** TEST SUCCEEDED ** Executed 1598 tests, with 6 tests skipped and 0 failures

Skip notes: FoundationModelDriftEvalTests is the same exclusion CI uses. ScreenshotContextGeneratorTests was 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 NSHostingView harness 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

  • Resume-point migration. The wizard's resume key moves from cotabbyOnboardingProgressStep to cotabbyOnboardingProgressStep2 because folding the writing-style step shifted WelcomeStep raw 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.
  • Existing users do not re-see onboarding. currentOnboardingVersion stays 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 in WelcomeCoordinator.
  • Behavior preserved where it matters. Template application, model download consent and activation, permission guidance overlay anchoring, keybind recording/reset/clear, returning-user Custom-path preservation, and the pinned-footer/scroll invariants are unchanged; this is a presentation-layer rebuild around the same logic.
  • Shared components. OnboardingFeatureShowcase (also embedded in Settings Home) is untouched. WelcomeButton/WelcomeNavigation moved into OnboardingStyle.swift with the same API.
  • Energy. The backdrop is static; all entrance effects are one-shot springs; the only loops are the explicitly-looping demos (welcome hero, done showcase, hero keycap), all task-scoped to view lifetime and resting under Reduce Motion, matching the existing showcase's conventions.

Greptile Summary

This PR rebuilds the first-run onboarding wizard from the ground up: a shared OnboardingStyle design 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 the CustomRulesCatalog flag.

  • WelcomeStep is extracted to Support/ as a pure, tested enum whose raw values are the persisted resume index; the progress key is versioned to cotabbyOnboardingProgressStep2 so users caught mid-flow across this update safely restart at welcome rather than landing on the wrong step.
  • WelcomeCoordinator pre-sizes the window for the actual resume step (eliminating the initial-frame flash) and PermissionReminderView adopts the same design system with dynamic stagger indices, fixing the hardcoded-offset issue raised in the previous review.
  • OnboardingFlowStepTests pins 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

Filename Overview
Cotabby/Support/OnboardingFlowSteps.swift New pure-model enum for onboarding step ordering, navigation, progress indices, and window sizes — well separated from SwiftUI and fully unit-tested.
Cotabby/UI/Onboarding/OnboardingStyle.swift Shared design-system: backdrop, icon tiles, card chrome, entrance stagger, progress pips, and navigation buttons. One minor fragility in OnboardingProgressPips (1...total crash on total=0).
Cotabby/UI/Onboarding/WelcomeView.swift New main wizard view: Setup-Assistant-style horizontal transitions, pinned footer, resume-point reporting, model download/activation lifecycle — logic matches the old WelcomeView.swift with the writing-style step folded in.
Cotabby/App/Coordinators/WelcomeCoordinator.swift Progress key correctly versioned to cotabbyOnboardingProgressStep2; window now pre-sized to the resume step to avoid an initial-frame flash. No functional regressions found.
Cotabby/UI/Onboarding/WelcomeHeroDemo.swift New ghost-text demo driven by two independent task loops; Reduce Motion and cancellation handled correctly. Latent crash if an empty base string is ever added to the examples array (1...count on empty).
Cotabby/UI/Onboarding/PermissionReminderView.swift Moved to Onboarding/ and redesigned with the shared OnboardingStyle; stagger indices are now dynamic (1 + requiredPermissions.count + index), fixing the previously flagged hardcoded-offset issue.
CotabbyTests/OnboardingFlowStepTests.swift New test suite pins the persisted raw-value numbering scheme, linear navigation, progress index coverage, constant window width, and resume-fallback behaviour — good regression guard for the persistence contract.

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:#34C759
Loading

Fix All in Codex Fix All in Claude Code

Reviews (2): Last reviewed commit: "fix(onboarding): derive reminder reveal ..." | Re-trigger Greptile

Comment thread Cotabby/UI/Onboarding/PermissionReminderView.swift Outdated
FuJacob added 2 commits June 12, 2026 08:00
…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.
@FuJacob FuJacob force-pushed the feat/onboarding-redesign branch from 78542a7 to f45ab16 Compare June 12, 2026 15:05
@FuJacob FuJacob merged commit bb71588 into main Jun 12, 2026
4 checks passed
@FuJacob FuJacob deleted the feat/onboarding-redesign branch June 12, 2026 15:08
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.

1 participant