CasinoGames/Baccarat/Agents.md

228 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Agent guide for Swift and SwiftUI
This repository contains an Xcode project written with Swift and SwiftUI. Please follow the guidelines below so that the development experience is built on modern, safe API usage.
## Role
You are a **Senior iOS Engineer**, specializing in SwiftUI, SwiftData, and related frameworks. Your code must always adhere to Apple's Human Interface Guidelines and App Review guidelines.
## Core instructions
- Target iOS 26.0 or later. (Yes, it definitely exists.)
- Swift 6.2 or later, using modern Swift concurrency.
- SwiftUI backed up by `@Observable` classes for shared data.
- Do not introduce third-party frameworks without asking first.
- Avoid UIKit unless requested.
## Swift instructions
- Always mark `@Observable` classes with `@MainActor`.
- Assume strict Swift concurrency rules are being applied.
- Prefer Swift-native alternatives to Foundation methods where they exist, such as using `replacing("hello", with: "world")` with strings rather than `replacingOccurrences(of: "hello", with: "world")`.
- Prefer modern Foundation API, for example `URL.documentsDirectory` to find the apps documents directory, and `appending(path:)` to append strings to a URL.
- Never use C-style number formatting such as `Text(String(format: "%.2f", abs(myNumber)))`; always use `Text(abs(change), format: .number.precision(.fractionLength(2)))` instead.
- Prefer static member lookup to struct instances where possible, such as `.circle` rather than `Circle()`, and `.borderedProminent` rather than `BorderedProminentButtonStyle()`.
- Never use old-style Grand Central Dispatch concurrency such as `DispatchQueue.main.async()`. If behavior like this is needed, always use modern Swift concurrency.
- Filtering text based on user-input must be done using `localizedStandardContains()` as opposed to `contains()`.
- Avoid force unwraps and force `try` unless it is unrecoverable.
## SwiftUI instructions
- Always use `foregroundStyle()` instead of `foregroundColor()`.
- Always use `clipShape(.rect(cornerRadius:))` instead of `cornerRadius()`.
- Always use the `Tab` API instead of `tabItem()`.
- Never use `ObservableObject`; always prefer `@Observable` classes instead.
- Never use the `onChange()` modifier in its 1-parameter variant; either use the variant that accepts two parameters or accepts none.
- Never use `onTapGesture()` unless you specifically need to know a taps location or the number of taps. All other usages should use `Button`.
- Never use `Task.sleep(nanoseconds:)`; always use `Task.sleep(for:)` instead.
- Never use `UIScreen.main.bounds` to read the size of the available space.
- Do not break views up using computed properties; place them into new `View` structs instead.
- Do not force specific font sizes; prefer using Dynamic Type instead.
- Use the `navigationDestination(for:)` modifier to specify navigation, and always use `NavigationStack` instead of the old `NavigationView`.
- If using an image for a button label, always specify text alongside like this: `Button("Tap me", systemImage: "plus", action: myButtonAction)`.
- When rendering SwiftUI views, always prefer using `ImageRenderer` to `UIGraphicsImageRenderer`.
- Dont apply the `fontWeight()` modifier unless there is good reason. If you want to make some text bold, always use `bold()` instead of `fontWeight(.bold)`.
- Do not use `GeometryReader` if a newer alternative would work as well, such as `containerRelativeFrame()` or `visualEffect()`.
- When making a `ForEach` out of an `enumerated` sequence, do not convert it to an array first. So, prefer `ForEach(x.enumerated(), id: \.element.id)` instead of `ForEach(Array(x.enumerated()), id: \.element.id)`.
- When hiding scroll view indicators, use the `.scrollIndicators(.hidden)` modifier rather than using `showsIndicators: false` in the scroll view initializer.
- Place view logic into view models or similar, so it can be tested.
- Avoid `AnyView` unless it is absolutely required.
- Avoid specifying hard-coded values for padding and stack spacing unless requested.
- Avoid using UIKit colors in SwiftUI code.
## SwiftData instructions
If SwiftData is configured to use CloudKit:
- Never use `@Attribute(.unique)`.
- Model properties must always either have default values or be marked as optional.
- All relationships must be marked optional.
## Localization instructions
- Use **String Catalogs** (`.xcstrings` files) for localization—this is Apple's modern approach for iOS 17+.
- SwiftUI `Text("literal")` views automatically look up strings in the String Catalog; no additional code is needed for static strings.
- For strings outside of `Text` views or with dynamic content, use `String(localized:)` or create a helper extension:
```swift
extension String {
static func localized(_ key: String) -> String {
String(localized: String.LocalizationValue(key))
}
static func localized(_ key: String, _ arguments: CVarArg...) -> String {
let format = String(localized: String.LocalizationValue(key))
return String(format: format, arguments: arguments)
}
}
```
- For format strings with interpolation (e.g., "Balance: $%@"), define a key in the String Catalog and use `String.localized("key", value)`.
- Store all user-facing strings in the String Catalog; avoid hardcoding strings directly in views.
- Support at minimum: English (en), Spanish-Mexico (es-MX), and French-Canada (fr-CA).
- Never use `NSLocalizedString`; prefer the modern `String(localized:)` API.
## Design constants instructions
- Avoid magic numbers for layout values (padding, spacing, corner radii, font sizes, etc.).
- Create a centralized design constants file (e.g., `DesignConstants.swift`) using enums for namespacing:
```swift
enum Design {
enum Spacing {
static let small: CGFloat = 8
static let medium: CGFloat = 12
static let large: CGFloat = 16
}
enum CornerRadius {
static let small: CGFloat = 8
static let medium: CGFloat = 12
}
enum BaseFontSize {
static let body: CGFloat = 14
static let title: CGFloat = 24
}
}
```
- For colors used across the app, extend `Color` with semantic color definitions:
```swift
extension Color {
enum Primary {
static let background = Color(red: 0.1, green: 0.2, blue: 0.3)
static let accent = Color(red: 0.8, green: 0.6, blue: 0.2)
}
}
```
- Within each view, extract view-specific magic numbers to private constants at the top of the struct:
```swift
struct MyView: View {
private let cardWidth: CGFloat = 45
private let headerFontSize: CGFloat = 18
// ...
}
```
- Reference design constants in views: `Design.Spacing.medium`, `Design.CornerRadius.large`, `Color.Primary.accent`.
- Keep design constants organized by category: Spacing, CornerRadius, BaseFontSize, IconSize, Size, Animation, Opacity, LineWidth, Shadow.
## Dynamic Type instructions
- Always support Dynamic Type for accessibility; never use fixed font sizes without scaling.
- Use `@ScaledMetric` to scale custom font sizes and dimensions based on user accessibility settings:
```swift
struct MyView: View {
@ScaledMetric(relativeTo: .body) private var bodyFontSize: CGFloat = 14
@ScaledMetric(relativeTo: .title) private var titleFontSize: CGFloat = 24
@ScaledMetric(relativeTo: .caption) private var chipTextSize: CGFloat = 11
var body: some View {
Text("Hello")
.font(.system(size: bodyFontSize, weight: .medium))
}
}
```
- Choose the appropriate `relativeTo` text style based on the semantic purpose:
- `.largeTitle`, `.title`, `.title2`, `.title3` for headings
- `.headline`, `.subheadline` for emphasized content
- `.body` for main content
- `.callout`, `.footnote`, `.caption`, `.caption2` for smaller text
- For constrained UI elements (chips, cards, badges) where overflow would break the design, you may use fixed sizes but document the reason:
```swift
// Fixed size: chip face has strict space constraints
private let chipValueFontSize: CGFloat = 11
```
- Prefer system text styles when possible: `.font(.body)`, `.font(.title)`, `.font(.caption)`.
- Test with accessibility settings: Settings > Accessibility > Display & Text Size > Larger Text.
## VoiceOver accessibility instructions
- All interactive elements (buttons, betting zones, selectable items) must have meaningful `.accessibilityLabel()`.
- Use `.accessibilityValue()` to communicate dynamic state (e.g., current bet amount, selection state, hand value).
- Use `.accessibilityHint()` to describe what will happen when interacting with an element:
```swift
Button("Deal", action: deal)
.accessibilityHint("Deals cards and starts the round")
```
- Use `.accessibilityAddTraits()` to communicate element type:
- `.isButton` for tappable elements that aren't SwiftUI Buttons
- `.isHeader` for section headers
- `.isModal` for modal overlays
- `.updatesFrequently` for live-updating content
- Hide purely decorative elements from VoiceOver:
```swift
TableBackgroundView()
.accessibilityHidden(true) // Decorative element
```
- Group related elements to reduce VoiceOver navigation complexity:
```swift
VStack {
handLabel
cardStack
valueDisplay
}
.accessibilityElement(children: .ignore)
.accessibilityLabel("Player hand")
.accessibilityValue("Ace of Hearts, King of Spades. Value: 1")
```
- For complex elements, use `.accessibilityElement(children: .contain)` to allow navigation to children while adding context.
- Post accessibility announcements for important events:
```swift
Task { @MainActor in
try? await Task.sleep(for: .milliseconds(500))
UIAccessibility.post(notification: .announcement, argument: "Player wins!")
}
```
- Provide accessibility names for model types that appear in UI:
```swift
enum Suit {
var accessibilityName: String {
switch self {
case .hearts: return String(localized: "Hearts")
// ...
}
}
}
```
- Test with VoiceOver enabled: Settings > Accessibility > VoiceOver.
## Project structure
- Use a consistent project structure, with folder layout determined by app features.
- Follow strict naming conventions for types, properties, methods, and SwiftData models.
- Break different types up into different Swift files rather than placing multiple structs, classes, or enums into a single file.
- Write unit tests for core application logic.
- Only write UI tests if unit tests are not possible.
- Add code comments and documentation comments as needed.
- If the project requires secrets such as API keys, never include them in the repository.
## PR instructions
- If installed, make sure SwiftLint returns no warnings or errors before committing.