All skills

Game feel ("juice") for Apple apps — celebration choreography, haptic vocabulary design, sound-effect layers, and the event×channel feedback audit. Use when big moments fall flat, when designing haptics or SFX, or when auditing whether every meaningful event actually reaches the user.

Use this Skill: https://skilld.dev/gh/rshankras/claude-code-apple-skills/game-feel

This session only. Nothing lands on disk.

haptic-design.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Haptic Design

Designing a haptic vocabulary — semantic, distinct, and centrally owned — rather than sprinkling generator calls through views.

API Decision Table

Need API Notes
Simple state-driven feedback in SwiftUI .sensoryFeedback(_:trigger:) (iOS 17+) Declarative; fine for .success, .selection, .impact on value changes
One-off imperative feedback, UIKit-style UIImpactFeedbackGenerator etc. Call prepare() first; limited to system presets
A custom vocabulary of distinct patterns Core Haptics (CHHapticEngine) The right choice once you have ≥4 semantic events; full intensity/sharpness control
Designer-authored waveforms AHAP files + CHHapticPatternPlayer Only worth it for signature audio-haptic sync moments

Rule of thumb: the moment you catch yourself choosing between .success and .impact(weight:) for game events, you've outgrown presets — build a Core Haptics vocabulary.

The Semantic-Vocabulary Architecture

One central service owns the engine; game code speaks in meanings, never in patterns:

enum HapticEvent {
    case start          // round/session begins
    case correct        // success tap
    case pass           // skip / failure tap
    case reveal         // content shown (card, letter, dare)
    case timerPulse     // gentle urgency (e.g. 10s left)
    case timerUrgent    // hard urgency (e.g. 5s left)
    case stop           // the signature interrupt (music stop, freeze, catch)
    case roundEnd       // round complete, score committed
    case winner         // the rarest, biggest pattern
}

@MainActor @Observable
final class HapticsService {
    private var engine: CHHapticEngine?
    private let supportsHaptics =
        CHHapticEngine.capabilitiesForHardware().supportsHaptics

    func fire(_ event: HapticEvent) {
        guard supportsHaptics else { return }          // silent no-op on Simulator/iPad
        startEngineIfNeeded()                          // lazy start on first use
        // build CHHapticPattern from events(for: event), play it
    }
}

Architecture rules (each prevents a real failure):

  • Lazy engine start on first fire, not in init — engine start is not free and may race app launch.
  • Capability-gate once (capabilitiesForHardware().supportsHaptics) so every call site can fire blindly; no availability checks leak into views.
  • Handle stoppedHandler / resetHandler by nulling the engine so the next fire restarts it — the system stops engines freely (audio interruptions, thermal).
  • Stop the engine on background (scenePhase change) and let lazy-start recover on foreground — a running engine in background wastes power and can be killed out from under you.
  • Inject as an optional seam (haptics: HapticsService? = nil in stores/engines) — unit tests pass nil; previews pass a throwaway.
  • Views get it via @Environment; only stores/engines fire game events (see single-owner rule in SKILL.md).

Vocabulary Design Rules

  1. Name events by meaning, not by pattern — .correct, not .doubleTapLight. The pattern can be retuned later without touching call sites.
  2. Signature moments get signature patterns. The freeze/stop moment of a music game, the spin of a wheel, the winner — each needs its own event. Reusing .roundEnd for the winner erases the climax (rarity gradient, SKILL.md).
  3. Escalation tiers are pattern pairs — .timerPulse and .timerUrgent should be the same shape at different intensity/sharpness so they read as "the same thing, more urgent", and their thresholds must match the visual escalation exactly.
  4. Continuous events for continuous moments. A spin deserves a .hapticContinuous with an intensity ramp (parameter curves), not repeated transients. Transients are for instants.
  5. Cover every event in the domain, then stop. Draw up the event×channel matrix (feedback-audit.md) first; if an event isn't in the matrix, it doesn't get a haptic.

Pattern Sketches (starting points, tune on device)

Event Shape
.start One medium transient (intensity 0.6, sharpness 0.4) — "we've begun"
.correct One crisp transient (0.8, 0.7)
.pass One soft dull transient (0.5, 0.25)
.timerPulse Light transient (0.4, 0.3) each second
.timerUrgent Same cadence, harder (0.8, 0.6)
.stop Heavy transient + 0.3s continuous rumble tail — unmistakable
.roundEnd Two transients 150ms apart
.winner Three ascending transients + continuous swell — the biggest thing you play

Pitfalls

❌ Double-fire

Engine fires on "music stopped" and the store fires on the same state change → user feels a stutter-buzz. One owner per event.

❌ Preset semantics for game events

UINotificationFeedbackGenerator().notificationOccurred(.success) for a winner — it's the same buzz every form in iOS uses. Signature moments deserve custom patterns.

❌ No user toggle

Core Haptics ignores any system setting — there is no global "haptics off" that covers you. Ship a settings toggle; store it in the service, not in every call site.

❌ Testing feel in the Simulator

The Simulator plays no haptics at all. Pattern code can be unit-tested (event → pattern mapping), but intensity/sharpness tuning is device-only work — schedule it.

✅ Do

Centralize; speak semantics; gate once; tune the rarest events to be the biggest; give users an off switch.

References

Source: SKILL.md on GitHub

No alerts2mo3 checks · Risk SAFE
  • Gen Agent Trust Hub2mo

    The skill is a comprehensive guide for managing haptics, sound, and motion ('juice') in Apple applications. It includes a structured audit methodology that requires an agent to inspect the project's source code. This automated analysis phase creates a surface for indirect prompt injection, as malicious code within the analyzed project could attempt to manipulate the agent's findings or reasoning. The skill correctly identifies that human decisions and device-based testing are necessary for final judgments.

  • Socket2mo

    No alerts

  • Snyk2mo

    Risk: LOW · No issues

Signed by skilld at 34fe932. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago
What it can do
Reads files
last_verified
2026-07-18
review_by
2027-06-22
os_version
iOS 26 / macOS 26
All 3 allowed tools
ReadGlobGrep

README badge

README badge for rshankras/claude-code-apple-skills/game-feel