From apple-dev
Generate TipKit infrastructure with inline/popover tips, rules, display frequency, and testing utilities. Use when adding contextual tips or feature discovery to an iOS/macOS app.
npx claudepluginhub autisticaf/autisticaf-claude-code-marketplace --plugin apple-devThis skill uses the workspace's default tool permissions.
> **First step:** Tell the user: "generators-tipkit-generator skill loaded."
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
First step: Tell the user: "generators-tipkit-generator skill loaded."
Generate a complete TipKit setup for contextual tips and feature discovery, including tip definitions, rules, display frequency, inline and popover presentation, and testing utilities.
Use this skill when the user:
Search for existing TipKit usage:
Glob: **/*Tip*.swift
Grep: "import TipKit" or "Tips.configure"
If found, ask user:
Ask user via AskUserQuestion:
What features need tips?
Tip presentation style? (per tip or general preference)
Rule types needed?
Display frequency?
Tip ordering?
Read the templates file for code patterns:
Read("templates.md")
Generate these files based on configuration:
Tips/ directory with one file per tip (e.g., SearchTip.swift, FilterTip.swift)Tips/TipEvents.swift - Centralized event definitionsTips/TipsConfiguration.swift - Tips.configure() setup and testing utilitiesCheck project structure:
Sources/ exists -> Sources/Tips/App/ exists -> App/Tips/Tips/Tips.configure() call in App entry pointTipView or .popoverTip() at the appropriate view locationsAfter generation, provide:
Sources/Tips/
├── SearchTip.swift # Tip with rules and options
├── FilterTip.swift # Another tip definition
├── TipEvents.swift # Centralized event definitions
└── TipsConfiguration.swift # Tips.configure() + testing helpers
App Entry Point (Required):
import TipKit
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.task {
try? Tips.configure([
.displayFrequency(.daily),
.datastoreLocation(.applicationDefault)
])
}
}
}
}
Inline Tip:
import TipKit
struct SearchView: View {
let searchTip = SearchTip()
var body: some View {
VStack {
TipView(searchTip)
SearchBar()
}
}
}
Popover Tip:
import TipKit
struct ToolbarView: View {
let filterTip = FilterTip()
var body: some View {
Button("Filter", systemImage: "line.3.horizontal.decrease.circle") {
// action
}
.popoverTip(filterTip)
}
}
Event Donation (at action site):
Button("Search") {
performSearch()
SearchTip.searchPerformed.donate()
}
Tip Invalidation (when tip is no longer relevant):
func onFeatureUsed() {
// User discovered the feature, invalidate the tip
searchTip.invalidate(reason: .actionPerformed)
}
Reset DataStore between runs:
// Add to a debug menu or call in preview
try? Tips.resetDatastore()
Show all tips for testing:
// Ignores rules and frequency -- shows everything
Tips.showAllTipsForTesting()
Show specific tips for testing:
Tips.showTipsForTesting([SearchTip.self])
Test scenarios:
Forgetting Tips.configure() -- Tips will never appear if you do not call Tips.configure() before any tip is displayed. This must happen early, typically in the App body or .task.
Rules not evaluating -- Parameter-based rules require you to set the parameter value explicitly. If you define @Parameter static var hasSeenFeature = false but never set it to true, the rule never passes.
DataStore conflicts in tests -- If you run unit tests and the app simultaneously, they may share the same DataStore. Use .datastoreLocation(.url(...)) to isolate them.
Display frequency blocking tips -- If you set .displayFrequency(.daily) and a tip was already shown today, no new tips will appear until tomorrow. Use .immediate during development.
Tips not dismissing after invalidation -- You must hold a reference to the tip instance and call .invalidate(reason:) on that instance. Creating a new instance and invalidating it does nothing to the displayed tip.
TipGroup ordering ignored -- Tips in a TipGroup only show in order if their rules are all satisfied. If Tip B's rules pass but Tip A's do not, neither will show (Tip A blocks Tip B).
.actionPerformed invalidation reason when the user completes the action the tip describesTipGroup when tips should appear in a logical sequenceTips.resetDatastore()Tips.configure() in the App entry point.immediate display frequency in production (overwhelming users)TipView inside a ScrollView without considering layout impact