Go to file
2026-02-16 16:30:12 -06:00
Sources/Bedrock Signed-off-by: Matt Bruce <mbrucedogs@gmail.com> 2026-02-16 16:30:12 -06:00
Tests/BedrockTests Signed-off-by: Matt Bruce <mbrucedogs@gmail.com> 2026-01-27 08:29:20 -06:00
.gitignore Initial commit: Bedrock design system and UI component library 2026-01-02 11:58:30 -06:00
Package.swift Remove macOS target - iOS only 2026-01-08 18:11:32 -06:00
README.md Signed-off-by: Matt Bruce <mbrucedogs@gmail.com> 2026-02-16 16:20:01 -06:00

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 Typography for each text element (.heading, .body, .caption, etc.)
  • Apply TextEmphasis for semantic colors (.primary, .secondary, .tertiary)
  • Use SectionHeader for grouped list section titles
  • Use Label.styled() for icon + text combinations

🎨 Theming (Required for all apps)

  • Read: THEME_GUIDE.md
  • Create [AppName]Theme.swift in Shared/Theme/
  • Define custom SurfaceColorProvider with your brand colors
  • Define custom AccentColorProvider for interactive elements
  • Create typealiases for easy access (e.g., AppSurface, AppAccent)
  • Import Bedrock: Add import Bedrock to all files using theme/design constants (Required)
  • Asset Catalog Format: Ensure Contents.json uses the "color" key and "luminosity" appearance (See THEME_GUIDE.md for 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.swift in Shared/
  • Define Color.Branding.primary, .secondary, .accent
  • Create AppIconConfig extension for your app
  • Create LaunchScreenConfig extension for your app
  • Create LaunchScreen.storyboard with matching brand color (Mandatory for no-flash launch)
  • Add INFOPLIST_KEY_UILaunchStoryboardName to build settings
  • Remove INFOPLIST_KEY_UILaunchScreen_* settings from project (Unreliable)
  • Wrap app entry point with AppLaunchView inside a ZStack
  • Generate and export app icon using IconGeneratorView

⚙️ Settings Screen (When adding settings)

  • Read: SETTINGS_GUIDE.md
  • Use SettingsToggle, SettingsSlider, SegmentedPicker components
  • Apply theme colors via AppSurface, AppAccent, etc.
  • Use SettingsCard for grouped sections
  • Use SettingsDivider between rows in cards
  • Use SettingsCardRow for custom rows inside cards
  • Use SettingsNavigationRow for navigation links
  • Avoid manual horizontal child padding inside SettingsCard (card owns row insets)
  • Add #if DEBUG section 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-environment via xcconfig (development/production)
  • Wire SwiftDataCloudKitSyncManager into app store lifecycle
  • Use SwiftDataRefreshThrottler for 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:

  1. First: Use Text.styled() for all text → Semantic typography + colors (see Usage below)
  2. Second: Read THEME_GUIDE.md → Create your app's color theme
  3. Third: Read BRANDING_GUIDE.md → Set up icons and launch screen
  4. 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.md for 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, .caption instead 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() with TextEmphasis instead of manually applying foregroundStyle(). 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.md for 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.