@hegemonart/get-design-done 1.16.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.claude-plugin/marketplace.json +12 -4
  2. package/.claude-plugin/plugin.json +22 -4
  3. package/CHANGELOG.md +111 -0
  4. package/README.md +27 -2
  5. package/agents/design-auditor.md +65 -1
  6. package/agents/design-context-builder.md +6 -1
  7. package/agents/design-doc-writer.md +21 -0
  8. package/agents/design-executor.md +22 -4
  9. package/agents/design-pattern-mapper.md +62 -0
  10. package/agents/design-phase-researcher.md +1 -1
  11. package/agents/motion-mapper.md +74 -9
  12. package/agents/token-mapper.md +8 -0
  13. package/package.json +16 -2
  14. package/reference/components/README.md +27 -23
  15. package/reference/components/alert.md +198 -0
  16. package/reference/components/badge.md +202 -0
  17. package/reference/components/breadcrumbs.md +198 -0
  18. package/reference/components/chip.md +209 -0
  19. package/reference/components/command-palette.md +228 -0
  20. package/reference/components/date-picker.md +227 -0
  21. package/reference/components/file-upload.md +219 -0
  22. package/reference/components/list.md +217 -0
  23. package/reference/components/menu.md +212 -0
  24. package/reference/components/navbar.md +211 -0
  25. package/reference/components/pagination.md +205 -0
  26. package/reference/components/progress.md +210 -0
  27. package/reference/components/rich-text-editor.md +226 -0
  28. package/reference/components/sidebar.md +211 -0
  29. package/reference/components/skeleton.md +197 -0
  30. package/reference/components/slider.md +208 -0
  31. package/reference/components/stepper.md +220 -0
  32. package/reference/components/table.md +229 -0
  33. package/reference/components/toast.md +200 -0
  34. package/reference/components/tree.md +225 -0
  35. package/reference/css-grid-layout.md +835 -0
  36. package/reference/data-visualization.md +333 -0
  37. package/reference/external/NOTICE.hyperframes +28 -0
  38. package/reference/form-patterns.md +245 -0
  39. package/reference/image-optimization.md +582 -0
  40. package/reference/information-architecture.md +255 -0
  41. package/reference/motion-advanced.md +754 -0
  42. package/reference/motion-easings.md +381 -0
  43. package/reference/motion-interpolate.md +282 -0
  44. package/reference/motion-spring.md +234 -0
  45. package/reference/motion-transition-taxonomy.md +155 -0
  46. package/reference/motion.md +20 -0
  47. package/reference/onboarding-progressive-disclosure.md +250 -0
  48. package/reference/output-contracts/motion-map.schema.json +135 -0
  49. package/reference/platforms.md +346 -0
  50. package/reference/registry.json +445 -220
  51. package/reference/registry.schema.json +4 -0
  52. package/reference/rtl-cjk-cultural.md +353 -0
  53. package/reference/user-research.md +360 -0
  54. package/reference/variable-fonts-loading.md +532 -0
  55. package/scripts/lib/easings.cjs +280 -0
  56. package/scripts/lib/parse-contract.cjs +220 -0
  57. package/scripts/lib/spring.cjs +160 -0
  58. package/scripts/tests/test-motion-provenance.sh +64 -0
@@ -0,0 +1,346 @@
1
+ # Platforms — Reference Guide
2
+
3
+ Platform conventions are not arbitrary constraints — they are the accumulated result of billions of user interactions on each operating system. When a designer deviates from a platform convention, they are implicitly asking their user to unlearn a trained reflex and replace it with a novel one specific to this product. That is expensive. This reference establishes the canonical interaction patterns, layout rules, gesture vocabularies, and component conventions for each platform the get-design-done framework targets, along with the governing rule for when brand expression should yield to platform habit and when it should not.
4
+
5
+ ---
6
+
7
+ ## 1. Navigation Patterns by Platform
8
+
9
+ Navigation is the skeleton of a product. Getting it wrong does not just inconvenience users — it makes the entire product feel alien on its own operating system. Each platform has developed a navigation idiom that users practice dozens of times per day across every app on the device. A product that violates that idiom creates friction on every single screen transition.
10
+
11
+ ### iOS
12
+
13
+ iOS navigation is built on a two-axis model: vertical hierarchy (drilling into content via a navigation stack managed by `UINavigationController` or SwiftUI's `NavigationStack`) and lateral switching (jumping between top-level sections via a `UITabBarController` or SwiftUI's `TabView`). The tab bar lives at the bottom of the screen and should contain between two and five destinations. Apple's Human Interface Guidelines are explicit that five tabs is the maximum — adding a sixth requires a "More" overflow pattern, which is a recognized user experience penalty.
14
+
15
+ The navigation bar at the top of the screen carries the current screen title and back button. The back button is automatically generated by the navigation stack with the title of the previous screen as its label when space permits, falling back to the word "Back." Never replace the system back button with a custom left-side icon that performs a different action — this violates user expectation so severely that it creates support tickets.
16
+
17
+ Hamburger menus (three-line "sandwich" icons triggering a side drawer) are a web and Android import. They are not idiomatic iOS and should not appear in native iOS apps. If a product has more destinations than five tabs can accommodate, the correct iOS solution is to reconsider the information architecture, not to add a drawer. Drawers exist in some iOS apps, but they are third-party patterns tolerated for legacy reasons, not blessed conventions.
18
+
19
+ ### Android
20
+
21
+ Android follows Material 3's navigation component system. The bottom navigation bar serves the same function as iOS's tab bar — lateral switching between top-level destinations — and should contain three to five destinations. Material 3 introduced the navigation rail as the preferred navigation surface on medium-width screens (tablets, foldables in unfolded state), where it appears as a vertical column of icons and labels on the leading edge of the layout. On large screens (desktop-class Android, Chromebook), a navigation drawer — either modal or persistent — replaces the rail.
22
+
23
+ The system back gesture on Android is an edge swipe from either the left or right side of the screen. Since Android 10 this is the system default, replacing the software back button in gesture navigation mode. Designs must never shadow this gesture with in-app behavior, because the OS intercepts it before the app's gesture recognizers fire. The back gesture always navigates up in the activity/fragment back stack or returns to the launcher; no design override is possible or appropriate.
24
+
25
+ ### Web
26
+
27
+ Web navigation has three dominant patterns, each suited to a different information architecture scale. Top navigation bars work for sites with five to eight primary sections whose names fit comfortably in a single horizontal row. Sidebars are the standard for application-density products (dashboards, admin tools, documentation sites) because they accommodate ten to thirty labeled destinations without cognitive overload, and they scale with the viewport rather than breaking. Mega-menus — large overlay panels triggered by hovering or clicking a top-nav item — suit e-commerce and marketing sites where category hierarchies are deep but users need cross-category discovery on every page.
28
+
29
+ The command palette, triggered by `Cmd+K` (macOS) or `Ctrl+K` (Windows/Linux), has become the power-user navigation layer for application-dense web products. It is not a replacement for structural navigation — it is an accelerator for users who already know where they want to go. Implementing a command palette without maintaining the sidebar or top nav for discoverability is a mistake; command palettes serve learners and experts differently, and both populations need to be served simultaneously.
30
+
31
+ ### visionOS
32
+
33
+ visionOS inhabits three-dimensional space, and its navigation conventions emerge from the affordances of spatial UI. Users look around and glance at windows rather than tapping a nav bar, so the concept of a persistent bottom bar — physically below the user's comfortable resting gaze — is inappropriate. Apple's spatial design guidelines introduce orbital menus: radial arrangements of controls that anchor to content and appear at the periphery of a window when activated, keeping the central content area unobstructed.
34
+
35
+ Window grouping is the visionOS analog of tab groups. Related windows can be positioned in the user's space as a coherent cluster, and the user navigates between them by glancing and reaching. The design implication is that each window should be self-sufficient and not require persistent navigation chrome — navigation is spatial rather than embedded in a UI surface. Because users can position windows anywhere in their environment, designers cannot rely on spatial relationships that were composed in the design tool; design for each window independently, not for a composed layout.
36
+
37
+ ### watchOS
38
+
39
+ watchOS navigation is scroll-first. The primary navigation surface is a scrollable list — the watch equivalent of a `UITableView` — optimized for the Digital Crown, which provides physical momentum scrolling. Users expect to scroll down to see more content on the current screen and to use the Digital Crown as the primary navigation gesture for list content. Tapping the Digital Crown navigates to the watch face; this gesture is reserved by the OS and cannot be shadowed.
40
+
41
+ Nested navigation should never exceed two levels on watchOS. The small screen area and the awkward input model (small touch targets, no text input without Siri) mean that deep navigation hierarchies become traps — users lose orientation and cannot easily escape. If a feature cannot be expressed in two navigation levels or fewer, it is too complex for watchOS and should be redesigned or moved to the companion iOS app.
42
+
43
+ ### Cross-Platform Consistency: Convention vs. Brand
44
+
45
+ The governing rule for resolving the tension between platform convention and brand identity is this: **follow the platform for navigation, interaction patterns, and component behavior; apply the brand to color, typography scale, iconography, and illustration.** A user who encounters a bottom tab bar on iOS and a bottom navigation bar on Android is experiencing appropriate platform adaptation, not inconsistent branding. A user who encounters a custom gesture that conflicts with the OS back gesture is experiencing a design error, regardless of how on-brand the interaction felt in the design tool.
46
+
47
+ Brand consistency lives in the visual layer — your colors, type choices, illustration style, and motion language should be recognizable across platforms without requiring you to break platform idioms to achieve them. When a component does not exist in your design system for a given platform (for example, a native alert dialog on iOS vs. Android), the correct approach is to adapt the component to the platform's idiom while keeping the copy, color, and brand voice consistent.
48
+
49
+ ---
50
+
51
+ ## 2. Safe Areas and Layout Margins
52
+
53
+ Every modern mobile platform introduces areas of the display where UI elements should not appear: behind the status bar, under the home indicator, behind the camera cutout, or outside the circular mask of a watch. Ignoring safe areas does not merely produce visual bugs — it can make controls unreachable or occluded in ways that break the product for large segments of users.
54
+
55
+ ### iOS: Notch, Dynamic Island, and Home Indicator
56
+
57
+ Since the iPhone X, iOS devices have a camera housing at the top of the display — originally the notch, now the Dynamic Island on newer devices — and a home indicator bar at the bottom. iOS exposes these as safe area insets, accessible in CSS via the environment function:
58
+
59
+ ```css
60
+ padding-top: env(safe-area-inset-top);
61
+ padding-right: env(safe-area-inset-right);
62
+ padding-bottom: env(safe-area-inset-bottom);
63
+ padding-left: env(safe-area-inset-left);
64
+ ```
65
+
66
+ For web content rendered in a WKWebView or Safari on iOS, the viewport meta tag must include `viewport-fit=cover` to opt in to edge-to-edge layout; without it, the browser automatically adds padding and the environment variables resolve to zero, making them useless:
67
+
68
+ ```html
69
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
70
+ ```
71
+
72
+ The home indicator at the bottom of the display on Face ID devices occupies approximately 34 points. Any interactive controls placed at the very bottom of the screen — primary action buttons, persistent toolbars, bottom sheets — must clear the home indicator. The system automatically applies the inset for native UIKit and SwiftUI layouts, but web-in-WebView requires the CSS above. Failing to handle the bottom inset is the single most common iOS layout bug in hybrid apps.
73
+
74
+ ### Android: Status Bar, Navigation Bar, and Edge-to-Edge
75
+
76
+ Android has enforced edge-to-edge rendering as the default since Android 15. Prior to this, apps could opt out of drawing behind the system bars; that escape hatch is now closed. Every app draws behind the status bar and the gesture navigation bar, and every app is responsible for inset handling.
77
+
78
+ Android exposes insets through `WindowInsetsCompat` in the Jetpack library. In Jetpack Compose, the `safeDrawing` inset padding modifier handles the most common cases. For React Native and Flutter apps targeting Android, the platform bridge handles inset forwarding, but custom navigation bars or bottom sheets still require explicit inset consumption.
79
+
80
+ The system gesture navigation bar at the bottom of the screen is transparent by default on Android 10 and later, showing the app content beneath it. This means a white bottom sheet on a white background will appear to have no bottom boundary — the bar blends in. The design solution is to draw content under the bar (which Android encourages) while ensuring the bottommost interactive control is above the gesture exclusion zone, which is approximately 30dp from the bottom edge.
81
+
82
+ ### Web: Viewport Units and Browser Chrome Behavior
83
+
84
+ The `100vh` viewport unit on mobile browsers has been a source of layout bugs for years. Mobile browsers (Safari on iOS, Chrome on Android) subtract their toolbar chrome from the viewport when the toolbar is shown, then restore that height when the toolbar hides as the user scrolls down. A bottom bar positioned at `bottom: 0; height: 100vh` will appear to jump as the browser chrome appears and disappears.
85
+
86
+ The correct unit is `dvh` (dynamic viewport height), introduced in the CSS Values Level 4 specification and supported in all modern mobile browsers as of 2023. `100dvh` tracks the visible viewport including chrome behavior. For elements that should be full-screen and must not resize, use `svh` (small viewport height, the minimum height when chrome is fully visible). For elements that should use all available space when chrome is hidden, use `lvh` (large viewport height). The table below summarizes:
87
+
88
+ | Unit | Resolves to | Use case |
89
+ |------|-------------|----------|
90
+ | `100vh` | Static — initial viewport height, ignores chrome | Avoid on mobile; use for desktop |
91
+ | `100dvh` | Dynamic — updates as browser chrome shows/hides | Default choice for full-height mobile layouts |
92
+ | `100svh` | Static — smallest possible viewport (chrome fully visible) | Fixed bottom bars that should never resize |
93
+ | `100lvh` | Static — largest possible viewport (chrome fully hidden) | Hero sections that expand when chrome hides |
94
+
95
+ ### watchOS: Circular Display Mask
96
+
97
+ The Apple Watch display has rounded corners and a circular mask that clips content outside a rounded-rectangle boundary on older models and an increasingly circular boundary on newer always-on display models. Content placed in the extreme corners of a 44mm or 45mm Watch layout will be clipped. The standard layout margin in SwiftUI on watchOS is 6pt on each horizontal edge; content within this margin is guaranteed to be visible. Images and full-bleed backgrounds should be designed to be visually effective even when corners are clipped.
98
+
99
+ ---
100
+
101
+ ## 3. Gesture Vocabularies
102
+
103
+ Gestures are the physical language of a platform. Each operating system has reserved certain gestures for system-level navigation, and these reservations cannot be overridden by applications — the OS claims them before the app's gesture recognizers run. Shadowing a reserved gesture does not produce a conflict; it produces a silent failure where the user's intended in-app action triggers the system behavior instead, and the app gesture is never received.
104
+
105
+ ### iOS Gesture Reservations
106
+
107
+ The most critical reserved gesture on iOS is the **swipe from the left edge of the screen**, which navigates back in the navigation stack. Any custom pan gesture that begins near the left edge will conflict with the system's interactive pop gesture recognizer. The correct handling is to disable the custom gesture when it would conflict, not to attempt to override the system behavior.
108
+
109
+ **Swipe down from the top of the screen** opens Notification Center. On Face ID devices, swiping down from the upper-left opens Notification Center and swiping down from the upper-right opens Control Center. Custom pull-to-refresh gestures that begin at the very top of the screen work because they begin from within the scrollable content area, not from the status bar region.
110
+
111
+ **Long press** on iOS surfaces context menus (UIContextMenu) or enters wiggle mode on home screen icons. In-app long press for custom behavior is acceptable as long as it is not the primary or only affordance for a critical action — users cannot discover long-press affordances without experimentation, so any feature requiring long press must also be reachable through a visible control.
112
+
113
+ **Pinch** zooms content in maps, images, and text. Applications can use pinch for custom scaling behaviors within a content view, but pinch should not be used as a navigation trigger (e.g., pinch to go back) because it conflicts with system-level zoom accessibility features.
114
+
115
+ **Force Touch / Haptic Touch** (long press with haptic response) is the iOS mechanism for quick actions and peek. It is available on all modern iOS devices. Use UIContextMenuInteraction for this behavior rather than attempting to detect touch pressure manually — the system API handles the haptic response and the visual presentation.
116
+
117
+ ### Android Gesture Reservations
118
+
119
+ The **edge swipe from either the left or right side of the screen** navigates back in the activity stack. This is identical in function to iOS's left-edge swipe but applies to both edges on Android. Applications can declare gesture exclusion rectangles — specific screen regions where the app claims swipe gestures — but these are limited to a maximum height of 200dp per region and cannot occupy the full screen height. Use gesture exclusion only for essential in-app swipe interactions like sliders and carousels that are positioned near the screen edge.
120
+
121
+ **Swipe up from the bottom** opens the app launcher/home screen or enters recents mode, depending on how far the swipe extends. This gesture cannot be intercepted or overridden by applications. Bottom sheets that need to be dragged upward must begin from a handle or content area clearly above the system gesture zone.
122
+
123
+ **Long press** on Android surfaces the contextual action menu and is widely used for multi-select patterns. Applications using long press for multi-select should follow Material Design's contextual action bar pattern — replacing the top app bar with an action bar that shows selection actions and a count of selected items.
124
+
125
+ ### Web Gesture Considerations
126
+
127
+ Web applications run inside a browser, which itself manages scroll, zoom, and navigation gestures. The `touch-action` CSS property allows web applications to declare which gestures they handle natively, preventing the browser from consuming those gestures. For a swipeable carousel, setting `touch-action: pan-y` tells the browser to handle vertical scrolling and pass horizontal swipes to the app's event listeners.
128
+
129
+ **Two-finger scroll** on trackpads and touchscreens is reserved for page scrolling and cannot be reliably shadowed for in-app use. Horizontal two-finger swipe in browsers navigates browser history (back/forward). Applications that use horizontal swipe for in-content navigation should be aware that this gesture will also trigger history navigation on some browser/OS combinations — a usability bug that is difficult to resolve without harming native browser back behavior.
130
+
131
+ ### visionOS Gesture Vocabulary
132
+
133
+ visionOS uses eye tracking combined with hand gestures. The primary interaction is look-and-tap: the user looks at a control (which highlights with a hover effect driven by eye tracking) and then performs a pinch gesture with thumb and index finger to activate it. Spatial pinch is the visionOS equivalent of a mouse click and should be treated as such — buttons and interactive controls designed for iOS translate directly.
134
+
135
+ **Drag** is performed by looking at a draggable element, pinching to grab, and moving the hand. Applications should not create drag interactions that require precise or sustained hand movement — the physical effort is significantly higher than a mouse drag, and prolonged gestures cause arm fatigue.
136
+
137
+ ### watchOS Gesture Vocabulary
138
+
139
+ The **Digital Crown** rotation is the signature watchOS input. It scrolls lists, adjusts values, and zooms maps. The Digital Crown single press navigates to the watch face; this is an absolute OS reservation. The Digital Crown button-press behavior cannot be customized by applications on watchOS.
140
+
141
+ **Horizontal swipes** navigate between pages in a PageTabViewStyle layout, which is the watchOS equivalent of a paged scroll view. This is the appropriate pattern for content that has a natural left-right sequence (steps in a process, days in a week). For non-sequential content, the scrollable list is preferable.
142
+
143
+ **Vertical swipes within a scrollable list** are the standard content navigation gesture and should not be given custom meaning. Applications that intercept vertical swipe for their own purposes will prevent list scrolling, which breaks the fundamental navigation model of the platform.
144
+
145
+ ---
146
+
147
+ ## 4. Platform-Specific Component Conventions
148
+
149
+ Components carry platform affordances encoded in their shape, behavior, and position. Using the wrong component variant on a given platform is not merely a visual inconsistency — it communicates a different action or intent to the user because the component's meaning is partially derived from its platform context.
150
+
151
+ ### Action Sheet vs. Bottom Sheet
152
+
153
+ On iOS, the action sheet (`UIActionSheet`, or `actionSheet` in SwiftUI) presents a set of choices related to the current context, anchored to the bottom of the screen on iPhone and presented as a popover on iPad. Action sheets are for choosing between a set of actions — they are not for arbitrary content. The Cancel button is always present at the bottom of the sheet and is the escape route.
154
+
155
+ On Android, the equivalent is the modal bottom sheet from Material Design. It serves a broader role than the iOS action sheet: it can contain lists of actions, but also form fields, detail content, or navigation. The Android bottom sheet does not have a mandatory Cancel button in the same position; instead, it is dismissed by tapping the scrim outside or by dragging it down. This behavioral difference means designs cannot be directly translated — an iOS action sheet with a prominent Cancel button will look wrong on Android because the dismiss convention differs.
156
+
157
+ ### Alert Dialog vs. Dialog
158
+
159
+ An iOS `UIAlertController` in alert style is a small centered dialog with a title, message, and up to two action buttons. When there are more than two actions, use the action sheet instead — the iOS alert is intentionally constrained to binary decisions. Alert dialogs block all interaction until dismissed.
160
+
161
+ Android's AlertDialog from Material Design is visually similar but accepts up to three buttons (positive, negative, neutral) and supports more complex layouts including dividers and scrollable content. The Android dialog also uses stronger typographic hierarchy than iOS alerts, following Material's `Title/Body/Actions` pattern explicitly.
162
+
163
+ Neither platform's alert dialog is appropriate for complex content, form input, or multi-step flows. For those, iOS uses presentation-style modal view controllers (full-screen or sheet), and Android uses full-screen dialogs or bottom sheets.
164
+
165
+ ### iOS Segmented Control vs. Android Tab Row
166
+
167
+ The iOS segmented control is a compact selector for switching between two to five mutually exclusive views or modes. It appears inline in the content area or in navigation bars, and its selection is reflected immediately — it is not a submit-style control. The segmented control is visually contained within a pill shape and does not have separate tab indicator lines.
168
+
169
+ Android's equivalent is the Tab layout from Material Design, which uses underline indicators on a row of text labels. Material 3 distinguishes between primary tabs (page-level navigation) and secondary tabs (content filtering within a page). The visual language is different enough that using an iOS segmented control design on Android will read as foreign. Design platform-specific variants for each; share only the component's logic and data model.
170
+
171
+ ### iOS Switch vs. Android Toggle
172
+
173
+ The iOS switch (UISwitch) is a pill-shaped binary toggle with a white circle thumb that slides horizontally. The on state uses the system accent color (blue by default). The animation is a smooth horizontal slide that makes the state change unambiguous.
174
+
175
+ Android's Material Design switch uses the same horizontal sliding metaphor but has a distinct visual grammar: a larger thumb that grows when dragged, an optional checkmark icon inside the thumb for the on state, and icon support for communicating the off state as well. Material 3 switches also support rounded and squircle thumb variants. The behavioral intention is identical, but the visual design is different enough that the components should be implemented separately per platform rather than sharing a single cross-platform design token.
176
+
177
+ ### Web Modal vs. Native Sheet
178
+
179
+ A web modal dialog (the HTML `<dialog>` element, or a custom overlay) blocks page interaction behind a scrim and centers a card in the viewport. It is the correct choice for confirmations, forms that require focus, and content previews when the user needs to complete or dismiss a task before continuing. Web modals work on both mouse and touch interfaces because they do not depend on the physical affordance of dragging a sheet from a panel edge.
180
+
181
+ Native bottom sheets (half-modal sheets in iOS, bottom sheets in Android) are appropriate for mobile-width layouts where the card anchored to the screen bottom provides a tactile affordance — users can drag the sheet down to dismiss it. On web, native sheet behavior can be approximated with CSS transitions and touch event handling, but it requires explicit engineering to match the physics of the native implementation. Reserve the sheet pattern for mobile web experiences; use centered modals for desktop web where sheets feel out of place.
182
+
183
+ ### visionOS: Ornaments vs. Toolbars
184
+
185
+ visionOS introduces the concept of ornaments — UI elements that appear to float outside the boundary of a window, anchored to its edge. The primary toolbar of a visionOS window should be placed in an ornament rather than inside the window's content area. This keeps the window's content area clean and takes advantage of the spatial depth available in visionOS to create a sense of UI layering. Toolbars inside windows flatten the spatial affordance of the platform and feel like web content rather than native visionOS design.
186
+
187
+ SwiftUI surfaces ornaments through the `.ornament` modifier, which anchors to a specified edge of the window at a specified offset. The recommended pattern is to place navigation controls (back, close, minimize) and contextual actions (edit, share, refresh) in an ornament anchored to the bottom or leading edge of the content window.
188
+
189
+ ---
190
+
191
+ ## 5. Native Typography
192
+
193
+ Platform typography is not merely a default font choice — it is a system of optical sizes, weights, tracking values, and dynamic scaling behaviors that the platform vendor has spent years calibrating for their display hardware. Using the native type system correctly means the product's text will look and respond identically to text in the OS and every other native app, which is the baseline users calibrate their reading experience against.
194
+
195
+ ### iOS: SF Pro, SF Rounded, and SF Compact
196
+
197
+ San Francisco (SF Pro) is the system typeface on iOS, macOS, and visionOS. It is a variable-weight sans-serif with separate Display (for text above approximately 20pt) and Text (for text at and below 20pt) optical sizes. The Display variant has tighter tracking optimized for large sizes; the Text variant has slightly looser tracking optimized for readability at small sizes. The transition between them happens automatically when using Apple's dynamic text styles — it does not happen automatically for custom font sizes, which is why specifying `UIFont.systemFont(ofSize:)` with sizes above 20pt while in a small-text context will produce tracking that looks subtly wrong.
198
+
199
+ SF Rounded is an alternate variant with softened terminals, appropriate for friendly or playful product tones. SF Mono is the monospaced variant, intended for code display, terminal output, and data values that must align in columns.
200
+
201
+ Dynamic Type is Apple's system for user-controlled text scaling. Users can set their preferred text size in Settings > Accessibility, which scales all text using the Dynamic Type styles up to a maximum multiplier of approximately 3×. Every text style in an iOS app should use a named Dynamic Type style (`UIFont.TextStyle` or SwiftUI's `.font(.body)`, `.font(.headline)`) to participate in this scaling. Never use text below 11pt at any Dynamic Type setting — below 11pt, letters collapse to the point of illegibility even on Retina displays. The minimum label size to target under standard accessibility settings is 13pt for body text, growing to as much as 53pt under the largest accessibility text size.
202
+
203
+ The canonical Dynamic Type scale for iOS, at the default (large) system text size:
204
+
205
+ | Style | Size | Weight | Leading |
206
+ |-------|------|--------|---------|
207
+ | Large Title | 34pt | Regular | 41pt |
208
+ | Title 1 | 28pt | Regular | 34pt |
209
+ | Title 2 | 22pt | Regular | 28pt |
210
+ | Title 3 | 20pt | Regular | 25pt |
211
+ | Headline | 17pt | Semibold | 22pt |
212
+ | Body | 17pt | Regular | 22pt |
213
+ | Callout | 16pt | Regular | 21pt |
214
+ | Subheadline | 15pt | Regular | 20pt |
215
+ | Footnote | 13pt | Regular | 18pt |
216
+ | Caption 1 | 12pt | Regular | 16pt |
217
+ | Caption 2 | 11pt | Regular | 13pt |
218
+
219
+ ### Android: Roboto, Noto, and Material 3 Type Scale
220
+
221
+ Roboto is the system typeface on Android. It is a geometric humanist sans-serif designed for screen rendering at varied pixel densities. Noto is the companion family for non-Latin scripts; when a character is not available in Roboto, the system falls back to the appropriate Noto variant. Products targeting global audiences on Android should ensure that their chosen custom typeface has sufficient Unicode coverage, or that their CSS/font stack includes Roboto and Noto as fallbacks for unsupported characters.
222
+
223
+ Material 3 defines a five-category type scale: Display, Headline, Title, Body, and Label, each with three sizes (Large, Medium, Small). Display and Headline are for large, expressive text in hero areas; Title is for component headings and section labels; Body is for paragraph content; Label is for compact UI text in buttons, chips, and captions.
224
+
225
+ | Token | Size | Weight | Line height |
226
+ |-------|------|--------|-------------|
227
+ | Display Large | 57sp | Regular (400) | 64sp |
228
+ | Display Medium | 45sp | Regular | 52sp |
229
+ | Display Small | 36sp | Regular | 44sp |
230
+ | Headline Large | 32sp | Regular | 40sp |
231
+ | Headline Medium | 28sp | Regular | 36sp |
232
+ | Headline Small | 24sp | Regular | 32sp |
233
+ | Title Large | 22sp | Regular | 28sp |
234
+ | Title Medium | 16sp | Medium (500) | 24sp |
235
+ | Title Small | 14sp | Medium | 20sp |
236
+ | Body Large | 16sp | Regular | 24sp |
237
+ | Body Medium | 14sp | Regular | 20sp |
238
+ | Body Small | 12sp | Regular | 16sp |
239
+ | Label Large | 14sp | Medium | 20sp |
240
+ | Label Medium | 12sp | Medium | 16sp |
241
+ | Label Small | 11sp | Medium | 16sp |
242
+
243
+ The `sp` unit (scale-independent pixels) on Android is equivalent to `dp` (density-independent pixels) at default font scale, but scales with the user's font size preference. Always use `sp` for text sizes, never `dp` or `px`, to respect accessibility text scaling preferences.
244
+
245
+ ### Web: System Font Stack and Fallback Logic
246
+
247
+ Web typography defaults should reach for the operating system's own UI font before loading a custom typeface. This approach provides the fastest perceived load time (no network request for the font), perfect rendering quality (the OS vendor has tuned the hinting for their own font), and visual consistency with the ambient UI the browser chrome is using.
248
+
249
+ The canonical cross-platform system font stack, in order of preference:
250
+
251
+ ```css
252
+ font-family:
253
+ system-ui,
254
+ -apple-system, /* Safari on macOS/iOS pre-system-ui support */
255
+ "Segoe UI", /* Windows 10/11 */
256
+ Roboto, /* Android, Chrome OS */
257
+ "Helvetica Neue", /* Older macOS */
258
+ Arial, /* Universal fallback */
259
+ sans-serif; /* Generic family declaration */
260
+ ```
261
+
262
+ `system-ui` is the CSS standardized keyword that resolves to the platform UI font. On macOS and iOS it resolves to SF Pro; on Android to Roboto; on Windows 11 to Segoe UI Variable. It is supported in all modern browsers and should be the first declaration in the stack. The `-apple-system` keyword predates `system-ui` standardization and remains useful as a fallback for older Safari versions. The explicit `"Segoe UI"` and `Roboto` declarations serve as fallbacks for contexts where `system-ui` is not supported.
263
+
264
+ When using a custom brand typeface on web, the stack should append the system font stack after the brand font, so that characters not covered by the brand font fall back gracefully rather than to a default serif or monospace.
265
+
266
+ ### watchOS: SF Compact
267
+
268
+ watchOS uses SF Compact, a narrower optical variant of San Francisco designed for the physical constraints of a 44mm or 45mm watch face. SF Compact's characters are wider-waisted and more circular than SF Pro, allowing the system to render more characters within the watch's narrow content width while maintaining readability. The guiding constraint for watchOS copy is extreme brevity: labels should be three words or fewer, and preferably fewer. Users glance at the watch for one to two seconds; they do not read sentences. Every watchOS text element should be evaluated by asking whether its meaning can be conveyed in fewer words. If it cannot, the feature may not be appropriate for the watch.
269
+
270
+ ---
271
+
272
+ ## 6. Haptic Feedback
273
+
274
+ Haptics are the tactile confirmation layer of mobile interfaces. They are the difference between an interface that feels alive under the finger and one that feels like touching a pane of glass. Used correctly, haptics confirm actions, communicate state transitions, and orient the user within a physical gesture. Used incorrectly — too frequently, too intensely, or for decorative purposes — they become noise that users disable in Settings, removing an entire feedback channel.
275
+
276
+ ### iOS: Taptic Engine
277
+
278
+ Apple's Taptic Engine is the haptic actuator present in all iPhones from iPhone 6s onward. iOS exposes three distinct haptic feedback APIs, each for a different use case.
279
+
280
+ `UIImpactFeedbackGenerator` communicates the physical metaphor of an impact — two objects colliding. It offers three styles: `.light`, `.medium`, and `.heavy`, corresponding to the perceived mass of the collision. Light is appropriate for small UI events like toggles and minor selections; medium for confirmations and modal presentations; heavy for destructive actions and notifications that demand attention. Use this generator when the user's action has a direct, immediate effect and you want to confirm the moment of contact.
281
+
282
+ `UINotificationFeedbackGenerator` communicates the outcome of a completed process. It has three types: `.success`, `.warning`, and `.error`. These should always be paired with their corresponding visual state change — a haptic success without a visible success state is confusing, and a haptic error without a visible error state is alarming without explanation. Do not use notification feedback for routine actions; reserve it for operations with binary outcomes that the user needs to know about.
283
+
284
+ `UISelectionFeedbackGenerator` communicates movement through a series of items — a picker wheel advancing one position, a slider snapping to a value. It produces a subtle rhythmic tick that matches the cadence of physical detents on a mechanical dial. Use it only for continuous selection gestures, not for discrete button taps.
285
+
286
+ The governing rule for iOS haptics is to trigger them from changes the user caused, not from changes the system initiated. Asynchronous events (incoming notifications, background data sync) should not trigger impact or selection haptics; they may use notification haptics only if the outcome is directly relevant to an action the user recently took.
287
+
288
+ ### Android: VibrationEffect and HapticFeedbackConstants
289
+
290
+ Android provides haptic feedback through two mechanisms depending on the use case. `HapticFeedbackConstants` is the high-level API accessed through `View.performHapticFeedback()` — it uses semantic constants that the system maps to hardware-appropriate vibration patterns. Relevant constants and their iOS equivalents:
291
+
292
+ | Android constant | iOS equivalent | Semantics |
293
+ |------------------|----------------|-----------|
294
+ | `KEYBOARD_TAP` | `.light` impact | Single character input |
295
+ | `VIRTUAL_KEY` | `.medium` impact | Button press |
296
+ | `LONG_PRESS` | `.medium` impact | Long press activation |
297
+ | `CONFIRM` | `.success` notification | Successful action completion |
298
+ | `REJECT` | `.error` notification | Failed or blocked action |
299
+ | `GESTURE_START` | `.light` impact | Beginning of a drag gesture |
300
+ | `GESTURE_END` | `.medium` impact | Completion of a drag gesture |
301
+
302
+ `VibrationEffect` (accessed via `Vibrator.vibrate(VibrationEffect)`) provides lower-level control for custom patterns, intensities, and compositions. For most application use cases, `HapticFeedbackConstants` is sufficient and preferable — it delegates pattern selection to the platform, which accounts for differences in actuator hardware across Android devices. A pattern tuned for a Pixel's linear resonant actuator will feel wrong on a budget device with an eccentric rotating mass vibrator.
303
+
304
+ Android 12 introduced `VibrationEffect.Composition`, which allows sequencing haptic primitives (ticks, clicks, thuds, spins) with custom durations and amplitudes. This is appropriate for games and rich interactive experiences; for standard application UI, prefer the semantic constants.
305
+
306
+ ### Web: navigator.vibrate()
307
+
308
+ The Web Vibration API (`navigator.vibrate(pattern)`) is supported primarily on Android Chrome. iOS Safari does not implement the Vibration API, and desktop browsers ignore it. This severely limits its utility as a universal web haptic strategy — any feature that depends on `navigator.vibrate()` will silently do nothing on half the target audience.
309
+
310
+ The appropriate use of `navigator.vibrate()` on web is limited to a single, clearly defined scenario: **critical confirmations on mobile web experiences where the user is performing an action with significant consequences**, such as confirming a payment or an irreversible deletion. In this narrow case, the haptic provides an additional confirmation signal on devices that support it, while the experience degrades gracefully to visual-only confirmation on devices that do not. Decorative haptics, haptic rhythm patterns, and haptics on every button tap are inappropriate for web — the unreliable cross-device support makes them an inconsistency rather than an enhancement.
311
+
312
+ Before triggering any haptic, always check for API availability:
313
+
314
+ ```js
315
+ if ('vibrate' in navigator) {
316
+ navigator.vibrate(10); // 10ms — brief confirmation tap
317
+ }
318
+ ```
319
+
320
+ Never use vibration patterns longer than 20ms for UI feedback; longer patterns feel like alerts rather than confirmations and will concern users who are not expecting a sustained vibration.
321
+
322
+ ---
323
+
324
+ ## 7. Brand Consistency vs. Platform Convention
325
+
326
+ Every product that ships on multiple platforms faces the same tension: the brand wants visual and behavioral unity across surfaces, while each platform has its own conventions that users expect. Resolving this tension incorrectly in either direction produces problems. Over-platforming — designing each version so differently that the product feels like separate products — creates brand confusion and multiplies design and engineering cost. Over-branding — enforcing visual and behavioral uniformity at the cost of platform conventions — produces products that feel foreign on every platform they ship to.
327
+
328
+ The resolution requires distinguishing between two categories of design decisions: **structural decisions** and **expressive decisions**.
329
+
330
+ Structural decisions define how the user navigates, interacts, and recovers from errors. Navigation patterns, gesture vocabularies, component behaviors, safe area handling, and accessibility features all live in this category. For structural decisions, always follow the platform convention. The cost of deviating is real user confusion — trained reflexes fire and produce the wrong outcome. No brand benefit is worth that cost.
331
+
332
+ Expressive decisions define what the product looks and feels like at a perceptual level. Color palette, typography selection and scale, iconography style, illustration character, motion personality, and copy voice all live in this category. For expressive decisions, always follow the brand. Users recognize the product as "the same product" because these decisions are consistent, not because the tab bar appears at the same Y position on every platform.
333
+
334
+ The practical application is as follows:
335
+
336
+ - Use the correct navigation component for each platform (tab bar on iOS, bottom nav bar on Android) but fill it with the brand's colors, icons, and typography.
337
+ - Use platform-native dialogs and action sheets with the brand's color for accent buttons, not custom-shaped containers that shadow the OS dialog.
338
+ - Never implement a custom gesture that conflicts with an OS-reserved gesture. Design the interaction within the gesture space the platform makes available.
339
+ - Never override platform safe area handling. If a design requires content to appear in an unsafe zone, the design is wrong — not the safe area.
340
+ - Always respect the platform's minimum touch target and accessibility text scaling requirements. These are not platform conventions; they are accessibility requirements, and meeting them is a baseline, not an aspiration.
341
+
342
+ The iOS Human Interface Guidelines, Material Design 3 documentation, and Microsoft Fluent 2 guidelines are the authoritative sources for platform structural decisions. When any detail in this reference conflicts with those sources, those sources take precedence — they are updated continuously and reflect current platform capabilities and requirements. This reference synthesizes those sources for the purposes of the get-design-done framework but does not replace them.
343
+
344
+ ---
345
+
346
+ *This reference governs all platform-targeting decisions within the get-design-done framework. Deviations from platform convention require explicit justification in `.design/DESIGN-CONTEXT.md` as a C-XX constraint, with rationale documented. Cross-references: [iOS HIG](https://developer.apple.com/design/human-interface-guidelines/), [Material Design 3](https://m3.material.io/), [Microsoft Fluent 2](https://fluent2.microsoft.design/).*