|
|
||
|---|---|---|
| Sources/Bedrock | ||
| Tests/BedrockTests | ||
| .gitignore | ||
| Package.swift | ||
| README.md | ||
Bedrock
A foundational design system and UI component library for building consistent, beautiful SwiftUI applications.
Overview
Bedrock is designed to be the foundation upon which apps are built, providing:
- Design System: Consistent spacing, typography, colors, and animations
- Color Protocols: Define consistent color naming with custom palettes per app
- Settings Components: Ready-to-use toggle, picker, and selector views
- Sound & Haptics: Generic sound manager with haptic feedback support
- Onboarding: First-time user experience and contextual hints
- Cloud Sync: Generic iCloud data synchronization
- Visual Effects: Confetti celebrations, pulsing animations
- Utilities: Device detection, debugging tools, and more
📚 Implementation Guides for AI Agents
Before implementing any Bedrock features in a new app, read the relevant guide(s) below. Each guide contains step-by-step instructions, templates, and troubleshooting information.
Guide Reference
| Guide | Path | Purpose |
|---|---|---|
| Typography Guide | Sources/Bedrock/Theme/TYPOGRAPHY_GUIDE.md |
Text styling with Text.styled(), typography, and text emphasis |
| Theme Guide | Sources/Bedrock/Theme/THEME_GUIDE.md |
Create custom color themes using Bedrock's protocol-based theming system |
| Branding Guide | Sources/Bedrock/Branding/BRANDING_GUIDE.md |
Set up app icons, launch screens, and branded launch animations |
| Settings Guide | Sources/Bedrock/Views/Settings/SETTINGS_GUIDE.md |
Build branded settings screens with reusable UI components |
| SwiftData CloudKit Guide | Sources/Bedrock/Storage/SWIFTDATA_CLOUDKIT_SETUP_GUIDE.md |
Configure SwiftData+iCloud sync with reusable Bedrock sync lifecycle utilities |
Implementation Checklist
Use this checklist when setting up a new app with Bedrock:
📝 Text Styling (Use First)
- Read:
TYPOGRAPHY_GUIDE.md - Use
Text.styled()for all text in your app - Choose appropriate
Typographyfor each text element (.heading,.body,.caption, etc.) - Apply
TextEmphasisfor semantic colors (.primary,.secondary,.tertiary) - Use
SectionHeaderfor grouped list section titles - Use
Label.styled()for icon + text combinations
🎨 Theming (Required for all apps)
- Read:
THEME_GUIDE.md - Create
[AppName]Theme.swiftinShared/Theme/ - Define custom
SurfaceColorProviderwith your brand colors - Define custom
AccentColorProviderfor interactive elements - Create typealiases for easy access (e.g.,
AppSurface,AppAccent) - Import Bedrock: Add
import Bedrockto all files using theme/design constants (Required) - Asset Catalog Format: Ensure
Contents.jsonuses the"color"key and"luminosity"appearance (SeeTHEME_GUIDE.mdfor template) - Legibility Alignment: Apply
.preferredColorScheme(.dark)to the root view if using a dark theme to ensure system text resolves to white (Required for legibility) - Apply theme colors to all views (never use hardcoded colors)
🚀 Branding & Launch Screen (Required for all apps)
- Read:
BRANDING_GUIDE.md - Create
BrandingConfig.swiftinShared/ - Define
Color.Branding.primary,.secondary,.accent - Create
AppIconConfigextension for your app - Create
LaunchScreenConfigextension for your app - Create
LaunchScreen.storyboardwith matching brand color (Mandatory for no-flash launch) - Add
INFOPLIST_KEY_UILaunchStoryboardNameto build settings - Remove
INFOPLIST_KEY_UILaunchScreen_*settings from project (Unreliable) - Wrap app entry point with
AppLaunchViewinside a ZStack - Generate and export app icon using
IconGeneratorView
⚙️ Settings Screen (When adding settings)
- Read:
SETTINGS_GUIDE.md - Use
SettingsToggle,SettingsSlider,SegmentedPickercomponents - Apply theme colors via
AppSurface,AppAccent, etc. - Use
SettingsCardfor grouped sections - Use
SettingsDividerbetween rows in cards - Use
SettingsCardRowfor custom rows inside cards - Use
SettingsNavigationRowfor navigation links - Avoid manual horizontal child padding inside
SettingsCard(card owns row insets) - Add
#if DEBUGsection for development tools
☁️ SwiftData + CloudKit Sync (When enabling cross-device data sync)
- Read:
SWIFTDATA_CLOUDKIT_SETUP_GUIDE.md - Enable iCloud/CloudKit + Push Notifications + Remote notifications background mode
- Configure
aps-environmentvia xcconfig (development/production) - Wire
SwiftDataCloudKitSyncManagerinto app store lifecycle - Use
SwiftDataRefreshThrottlerfor minimum-interval refresh gates - Add a root-level refresh version observation for reliable UI invalidation
- Validate with two physical devices and CloudKit Console checks
Quick Start Order
When building a new app from scratch:
- First: Use
Text.styled()for all text → Semantic typography + colors (see Usage below) - Second: Read
THEME_GUIDE.md→ Create your app's color theme - Third: Read
BRANDING_GUIDE.md→ Set up icons and launch screen - Fourth: Read
SETTINGS_GUIDE.md→ Build your settings view
💡 Key Principle: Always prefer
Text("Hello").styled(.heading)over raw.font()and.foregroundStyle()calls. This ensures consistent styling and makes your code more readable.
Installation
Add Bedrock as a dependency in your Package.swift:
dependencies: [
.package(url: "ssh://git@192.168.1.128:220/mbrucedogs/Bedrock.git", branch: "master")
]
Then add it to your target:
.target(
name: "YourApp",
dependencies: ["Bedrock"]
)
Usage
⭐ Text Styling (Start Here)
The Text.styled() extension is the preferred way to style all text in Bedrock apps. It combines typography and color emphasis into a single, semantic API.
📖 Full Documentation: See
TYPOGRAPHY_GUIDE.mdfor complete typography options, text emphasis levels, and examples.
import SwiftUI
import Bedrock
// ✅ Preferred: Use styled() for all text
Text("Welcome Back")
.styled(.heroBold)
Text("Your profile is up to date")
.styled(.body, emphasis: .secondary)
Text("Last updated 5 min ago")
.styled(.caption, emphasis: .tertiary)
// Labels also support styled()
Label("Settings", systemImage: "gear")
.styled(.subheading)
// Section headers for grouped lists
SectionHeader("General")
SectionHeader("Notifications", icon: "bell.fill")
Why Use styled() First
- Single source of truth: Combines font + color in one call
- Semantic naming: Use
.heading,.body,.captioninstead of raw fonts - Theme-aware: Colors automatically adapt to your registered theme
- Readable code:
Text("Hello").styled(.heading)is clearer than chaining modifiers
Design Constants
Use the Design enum for consistent spacing, sizing, and styling:
import SwiftUI
import Bedrock
struct MyView: View {
var body: some View {
VStack(spacing: Design.Spacing.medium) {
Text("Hello")
.styled(.title)
.padding(Design.Spacing.large)
Button("Tap Me") { }
.clipShape(.rect(cornerRadius: Design.CornerRadius.medium))
}
}
}
Color System
Bedrock provides a protocol-based color system that enforces consistent naming while allowing apps to define their own palettes.
💡 For Text Colors: Use
Text.styled()withTextEmphasisinstead of manually applyingforegroundStyle(). See the Text Styling section above.
Using Default Colors
Bedrock includes neutral default colors that work out of the box:
// ✅ Preferred for text: Use styled()
Text("Primary Text")
.styled(.body)
Text("Secondary Text")
.styled(.body, emphasis: .secondary)
// For non-text elements, use Color extensions
VStack { }
.background(Color.Surface.primary)
Creating Custom Color Themes
Apps can define custom color palettes by conforming to the color protocols:
// Define custom accent colors
public enum MyAppAccentColors: AccentColorProvider {
public static let primary = Color(red: 0.9, green: 0.75, blue: 0.3)
public static let light = Color(red: 1.0, green: 0.85, blue: 0.4)
public static let dark = Color(red: 0.7, green: 0.55, blue: 0.2)
public static let secondary = Color(red: 0.2, green: 0.7, blue: 0.7)
}
// Create a complete theme
public enum MyAppTheme: AppColorTheme {
public typealias Surface = DefaultSurfaceColors // Reuse Bedrock defaults
public typealias Text = DefaultTextColors
public typealias Accent = MyAppAccentColors // Custom accents
public typealias Button = DefaultButtonColors
public typealias Status = DefaultStatusColors
public typealias Border = DefaultBorderColors
public typealias Interactive = DefaultInteractiveColors
}
// Use in views
Button("Action") { }
.background(MyAppTheme.Accent.primary)
Available Color Protocols
| Protocol | Properties |
|---|---|
SurfaceColorProvider |
primary, secondary, tertiary, overlay, card, groupedFill, sectionFill |
TextColorProvider |
primary, secondary, tertiary, disabled, placeholder, inverse |
AccentColorProvider |
primary, light, dark, secondary |
ButtonColorProvider |
primaryLight, primaryDark, secondary, destructive, cancelText |
StatusColorProvider |
success, warning, error, info |
BorderColorProvider |
subtle, standard, emphasized, selected |
InteractiveColorProvider |
selected, hover, pressed, focus |
Sound & Haptics
Generic sound manager that works with any app-defined sounds:
// Define your app's sounds
enum MyAppSound: String, AppSound {
case success, error, notification
var resourceName: String { rawValue }
var resourceExtension: String { "mp3" }
var bundle: Bundle { .main }
var fallbackSystemSoundID: UInt32? { nil }
}
// Play sounds and haptics
let soundManager = SoundManager.shared
soundManager.play(MyAppSound.success)
soundManager.playHaptic(.success)
soundManager.playHaptic(.light)
Onboarding State
Track first-time user experience and contextual hints:
@Observable
class AppState {
let onboarding = OnboardingState(appIdentifier: "myApp")
var showWelcome: Bool {
!onboarding.hasCompletedWelcome
}
}
// Register hints for skip functionality
onboarding.registerHintKeys("firstBet", "settings", "tutorial")
// Check if hints should show
if onboarding.shouldShowHint("firstBet") {
// Show hint
onboarding.markHintShown("firstBet")
}
// Complete onboarding
onboarding.completeWelcome()
Cloud Sync
Generic iCloud synchronization for app data:
// Define your persisted data
struct MyAppData: PersistableData {
static var dataIdentifier = "myApp"
static var empty = MyAppData()
var syncPriority: Int { score }
var lastModified: Date = .now
var score: Int = 0
}
// Create sync manager
let syncManager = CloudSyncManager<MyAppData>()
// Access and modify data
syncManager.data.score += 10
syncManager.save()
Visual Effects
Confetti
ZStack {
MainContentView()
if showCelebration {
ConfettiView(colors: [.red, .blue, .gold], count: 50)
}
}
Pulsing Attention
Button("Tap Here") { }
.pulsing(isActive: shouldHighlight, color: .white)
Settings Components
Ready-to-use settings UI components:
// Toggle with title and subtitle
SettingsToggle(
title: "Notifications",
subtitle: "Receive push notifications",
isOn: $notificationsEnabled
)
// Slider with format helpers
SettingsSlider(
title: "Brightness",
subtitle: "Adjusts the brightness",
value: $brightness,
format: SliderFormat.percentage,
leadingIcon: Image(systemName: "sun.min"),
trailingIcon: Image(systemName: "sun.max.fill")
)
// Segmented picker
SegmentedPicker(
title: "Theme",
options: [("Light", "light"), ("Dark", "dark")],
selection: $theme
)
// Selectable row with badge
SelectableRow(
title: "Premium Plan",
subtitle: "Unlock all features",
isSelected: plan == .premium,
badge: { BadgePill(text: "$9.99", isSelected: plan == .premium) },
action: { plan = .premium }
)
Debug Tools
MyComplexView()
.debugBorder(isDebugMode, color: .red, label: "Header")
Device Detection
Adapt your UI based on device characteristics:
if DeviceInfo.isPad {
SidebarView()
} else {
TabBarView()
}
if DeviceInfo.isLandscape {
HorizontalLayout()
}
Styling Quick Reference
| What You're Styling | Preferred Approach |
|---|---|
| Any text | Text("...").styled(.typography, emphasis: .level) |
| Labels | Label("...", systemImage: "...").styled(...) |
| Section titles | SectionHeader("...") |
| Spacing | Design.Spacing.medium, .large, etc. |
| Corner radius | Design.CornerRadius.medium, .large, etc. |
| Backgrounds | Color.Surface.primary, .card, etc. |
| Accent/brand colors | Color.Accent.primary, .secondary, etc. |
| Status indicators | Color.Status.success, .error, etc. |
📖 See Also:
TYPOGRAPHY_GUIDE.mdfor detailed do's and don'ts with text styling.
Design System Reference
Spacing
| Name | Value | Usage |
|---|---|---|
xxxSmall |
1pt | Hairline spacing |
xxSmall |
2pt | Minimal spacing |
xSmall |
4pt | Tight spacing |
small |
8pt | Compact spacing |
medium |
12pt | Default spacing |
large |
16pt | Comfortable spacing |
xLarge |
20pt | Generous spacing |
xxLarge |
24pt | Section spacing |
xxxLarge |
32pt | Large section spacing |
Opacity
| Name | Value | Usage |
|---|---|---|
verySubtle |
0.05 | Barely visible |
subtle |
0.1 | Subtle backgrounds |
hint |
0.2 | Hints and disabled states |
light |
0.3 | Light overlays |
medium |
0.5 | Medium emphasis |
strong |
0.7 | Strong emphasis |
heavy |
0.8 | Heavy overlays |
almostFull |
0.9 | Nearly opaque |
Animation
| Name | Value | Usage |
|---|---|---|
quick |
0.3s | Quick transitions |
standard |
0.5s | Standard animations |
springDuration |
0.4s | Spring animations |
staggerDelay |
0.1s | Staggered animations |
Requirements
- iOS 18.0+
- macOS 15.0+
- Swift 6.0+
License
Proprietary - All rights reserved.