13 KiB
| phase | slug | status | shadcn_initialized | preset | created |
|---|---|---|---|---|---|
| 31 | puter.js-zero-config-cloud | draft | true | new-york / neutral / cssVariables | 2026-04-02 |
Phase 31 — UI Design Contract
Visual and interaction contract for Phase 31: Puter.js Zero-Config Cloud. Generated by gsd-ui-researcher. Verified by gsd-ui-checker.
Design System
| Property | Value |
|---|---|
| Tool | shadcn |
| Preset | new-york, baseColor: neutral, cssVariables: true, style: new-york |
| Component library | Radix UI (via shadcn) |
| Icon library | lucide-react |
| Font | System UI (inherited from body; no custom font declared in index.css) |
Source: /opt/nexus/ui/components.json + /opt/nexus/ui/src/index.css
Spacing Scale
Declared values (must be multiples of 4):
| Token | Value | Usage |
|---|---|---|
| xs | 4px | Icon gaps (gap-1), inline badge padding |
| sm | 8px | Compact element spacing (gap-2), within-form row gaps |
| md | 16px | Default element spacing (gap-4), form field gaps |
| lg | 24px | Section padding (p-6), card interior padding |
| xl | 32px | Layout gaps (p-8) — matches existing wizard card p-8 |
| 2xl | 48px | Major section breaks — not used in wizard context |
| 3xl | 64px | Page-level spacing — not used in wizard context |
Exceptions:
- Touch targets:
min-height: 44pxenforced globally via@media (pointer: coarse)inindex.css— no per-component override required. - Provider option cards:
p-4(16px) interior padding, matchingModeSelectorcard pattern. - Warning callout (Google OAuth risk):
px-3 py-2(12px/8px) — compact inline alert pattern matching existing error state style.
Source: existing NexusOnboardingWizard.tsx uses p-8, gap-6, gap-4, gap-2. ModeSelector uses p-4, gap-3, gap-1.
Typography
| Role | Size | Weight | Line Height |
|---|---|---|---|
| Body | 14px (0.875rem) | 400 | 1.5 |
| Heading | 24px (1.5rem / text-2xl) | 600 | 1.2 |
| Caption / muted | 12px (0.75rem / text-xs) | 400 | 1.4 |
Notes:
- Heading size matches existing wizard
h1(text-2xl font-semibold) — locked by Phase 30 component pattern. - Label size matches existing form label pattern (
text-sm font-medium). - Body size matches existing paragraph + description pattern (
text-sm). - Caption is used for step indicator (
text-xs text-muted-foreground), provider descriptions, and warning footnotes. - No display-size text (>24px) is needed in this phase — the wizard card is constrained to
max-w-md.
Source: NexusOnboardingWizard.tsx lines 214, 245, 281–283, 294.
Color
All values are shadcn CSS custom properties resolved from /opt/nexus/ui/src/index.css.
Both light (Catppuccin Latte) and dark (Catppuccin Mocha) themes are supported.
| Role | Light value | Dark value | Usage |
|---|---|---|---|
| Dominant (60%) | --background (#eff1f5) |
--background (#1e1e2e) |
Wizard backdrop, page background |
| Secondary (30%) | --card (#e6e9ef) |
--card (#181825) |
Wizard card surface, provider option cards |
| Accent (10%) | --primary (#1e66f5) |
--primary (#89b4fa) |
Selected provider card border + tint, primary CTA button |
| Destructive | --destructive (#d20f39) |
--destructive (#f38ba8) |
Google OAuth policy-risk warning text; error state text |
Accent reserved for:
- The currently selected provider option card border (
border-primary) and tint (bg-primary/5) - The primary CTA button ("Continue with Puter", "Continue", "Get Started")
- The focus ring on interactive inputs and buttons (
--ring)
Do NOT use accent on: provider logos, status badges, neutral labels, section headings.
Source: index.css CSS custom properties; ModeSelector.tsx selected-state pattern (border-primary bg-primary/5).
Component Inventory
New components introduced in this phase:
| Component | File | Reuses |
|---|---|---|
ProviderSelectionStep |
ui/src/components/onboarding/ProviderSelectionStep.tsx |
Button, cn, NexusOnboardingWizard card patterns |
PuterAuthButton |
ui/src/components/onboarding/PuterAuthButton.tsx |
Button (variant default), lucide LogIn icon |
GoogleOAuthButton |
ui/src/components/onboarding/GoogleOAuthButton.tsx |
Button (variant outline), lucide AlertTriangle icon for warning |
ApiKeyEntryForm |
ui/src/components/onboarding/ApiKeyEntryForm.tsx |
Input, Label, Button |
ProviderRiskWarning |
inline in GoogleOAuthButton |
styled div with text-destructive + bg-destructive/10 — matches existing error block |
Existing components consumed without modification:
| Component | Source |
|---|---|
Button |
@/components/ui/button |
Input |
@/components/ui/input |
Label |
@/components/ui/label |
Skeleton |
@/components/ui/skeleton |
NexusOnboardingWizard |
@/components/NexusOnboardingWizard — extended with new Step 4 |
Interaction Contract
Wizard Step Extension
The existing 3-step wizard becomes a 4-step wizard for users without a detected local adapter:
Step 1: Hardware Detection → Step 2: Mode Selection → Step 3: Provider Selection (NEW) → Step 4: Root Directory
For users with a detected local adapter (hermes_local or claude_local), Step 3 is shown but pre-populated with the detected provider highlighted and a "Continue" shortcut.
Step indicator text: "Step {N} of 4" (updated from current "Step {N} of 3").
Provider Selection Step Layout
Three option cards in a vertical stack (matching ModeSelector grid pattern):
-
Puter (free, zero-config) — primary recommendation when no local AI and no API key
- Card border:
border-primary bg-primary/5when selected - Action: "Continue with Puter" button appears below cards when Puter is selected
- Auth state: button shows spinner during
puter.auth.signIn()popup - Post-auth state: button label changes to "Puter connected — Continue", icon:
CheckCircle(lucide), border staysborder-primary
- Card border:
-
Google (Gemini free tier) — shown with risk callout
- Risk callout: amber/destructive inline alert (see Copywriting section) rendered inside the card when this option is selected — always visible before the "Sign in with Google" button is enabled
- Action: "Sign in with Google" (disabled until risk callout has been displayed for 3 seconds — anti-accidental-click gate)
- Post-auth state: "Google connected — Continue"
-
API Key (subscription providers) — manual entry
- When selected: inline form expands below card (no new page) with provider select dropdown + API key input
- Supported providers listed in dropdown: OpenAI, Anthropic, Groq (extensible)
-
Skip for now — ghost button below the three cards, always visible
- Does not require a selection; proceeds to Step 4 with the probed default adapter
Loading States
| State | Treatment |
|---|---|
| Puter auth popup in progress | Button disabled, spinner icon (h-4 w-4 animate-spin), label "Connecting to Puter…" |
| Google OAuth in progress | Button disabled, spinner, label "Signing in…" |
| API key saving | Submit button disabled, spinner, label "Saving…" |
| Adapter probe in progress | Provider cards render with Skeleton placeholders where pre-detected tool badges would appear; probe is fire-and-forget (cards still interactive) |
Error States
All errors render inline below the triggering element using the existing error block pattern:
<p className="text-sm text-destructive bg-destructive/10 rounded-md px-3 py-2">
{errorMessage}
</p>
Keyboard and Accessibility
- All provider option cards are
<button type="button">elements (matching ModeSelector pattern) — keyboard navigable, focus ring via--ring. - Risk warning callout uses
role="alert"so screen readers announce it immediately when the Google option is selected. - Auth buttons have
aria-busy="true"during loading states. - Skip button has accessible label: "Skip provider setup for now".
Copywriting Contract
| Element | Copy |
|---|---|
| Step heading (provider step) | "Choose a provider" |
| Step subheading | "No API keys needed for the zero-config path." |
| Primary CTA — Puter | "Continue with Puter" |
| Primary CTA — Google | "Sign in with Google" |
| Primary CTA — API key | "Save API key" |
| Primary CTA — generic Continue | "Continue" |
| Skip action | "Skip for now" |
| Puter card label | "Puter — free, zero-config" |
| Puter card description | "Free AI powered by your Puter.com account. No API key needed." |
| Puter cost attribution note | "Usage is billed to your Puter account, not to Nexus." |
| Google card label | "Google — Gemini free tier" |
| Google card description | "Sign in with Google to access Gemini via your Google account." |
| Google risk warning heading | "Policy risk — read before continuing" |
| Google risk warning body | "Google has suspended accounts that used third-party apps with Gemini credentials. This may affect your Gmail and Workspace access. Use a Google AI Studio API key instead if you want to avoid this risk." |
| Google safe alternative hint | "Safer option: enter a Gemini API key from Google AI Studio below." |
| API key card label | "API key — subscription provider" |
| API key card description | "Use your own OpenAI, Anthropic, or Groq API key." |
| Puter connected success | "Puter connected — Continue" |
| Google connected success | "Google connected — Continue" |
| Empty state (no provider selected, user tries to continue without skipping) | Not applicable — "Skip for now" is always available; no blocking empty state. |
| Error: Puter popup blocked | "Puter sign-in was blocked. Click 'Continue with Puter' directly — do not use keyboard shortcuts." |
| Error: Puter auth failed | "Puter sign-in failed. Check your Puter.com account and try again." |
| Error: Google auth failed | "Google sign-in failed. Try again or use an API key instead." |
| Error: API key save failed | "Could not save API key. Check the key is valid and try again." |
| Error: generic setup failure | "Setup failed. Please try again." |
| Puter auth button loading | "Connecting to Puter…" |
| Google auth button loading | "Signing in…" |
| API key submit loading | "Saving…" |
| Auto-detected tool badge | "{ToolName} detected" (e.g. "Hermes detected", "Claude Code detected") |
| Step indicator | "Step {N} of 4" |
Destructive actions: None in this phase. The Google OAuth risk warning is a caution, not a destructive action confirmation (no data is deleted).
Registry Safety
| Registry | Blocks Used | Safety Gate |
|---|---|---|
| shadcn official (ui.shadcn.com) | button, input, label, skeleton, dialog | not required |
| Third-party | none | not applicable |
No third-party shadcn registry blocks are used in this phase. @heyputer/puter.js is an npm package loaded via CDN script tag at runtime (not a shadcn registry block) — registry vetting gate does not apply.
Notes for Executor
-
Wizard step count: Update the "Step N of 3" indicator to "Step N of 4" in
NexusOnboardingWizard.tsx. The existing step counter is a plain string — a one-line change. -
Puter CDN load: Load
https://js.puter.com/v2/dynamically vialoadScript()helper only when the user clicks "Continue with Puter" — not on wizard open. This avoids loading a large third-party script unnecessarily. -
Google risk warning timing gate: The "Sign in with Google" button must remain disabled for 3 seconds after the Google card is selected to prevent accidental clicks. Use a
useEffectwith asetTimeoutkeyed to the selected card state. -
Provider card pre-detection: Run
agentsApi.probeAdapter()forclaude_local,hermes_local, andopenclaw_gatewaywhen the wizard opens (parallel, fire-and-forget). Detected tools surface as atext-xs text-primarybadge inside the card ("Hermes detected"). Non-detected tools show nothing extra. -
Skip-all valid state: When the user skips Step 3 entirely, the wizard must still complete Step 4 (root directory) and create at least one working agent. The existing
defaultAdapterprobe result handles this — if hermes_local was detected, it's used; otherwise claude_local. -
No new shadcn components needed: All required UI elements are covered by the existing component inventory (button, input, label, skeleton). Do not install additional shadcn components for this phase.
Checker Sign-Off
- Dimension 1 Copywriting: PASS
- Dimension 2 Visuals: PASS
- Dimension 3 Color: PASS
- Dimension 4 Typography: PASS
- Dimension 5 Spacing: PASS
- Dimension 6 Registry Safety: PASS
Approval: pending