Return...

Ein Zen-Meditations- und Fokus-Timer auf fünf Bildschirmen: iPhone, iPad, Apple Watch, Apple TV und Mac.

Veröffentlicht am 21. April 2026. Eine Codebase. Siebenundzwanzig Sprachen, darunter Arabisch und Hebräisch. Vier Themen, drei Glocken, keine Analytics. Im Folgenden geht es darum, wie das Ganze zusammenkam: die technischen Entscheidungen, die gestalterischen Abwägungen und der lange, stille Prozess, Hunderte KI-generierter Wassertropfen auf einen einzigen zu reduzieren.

Universell

Eine Codebase, fünf Bildschirme.

Return ist die erste App, die ich veröffentlicht habe, die aus einem einzigen Xcode-Projekt auf jeder Apple-Bildschirmklasse läuft: iPhone, iPad, Apple Watch, Apple TV und Mac. Siebenundfünfzig Swift-Dateien, rund 12.700 Codezeilen und keine einzige externe Abhängigkeit. Reines SwiftUI, AVFoundation, HealthKit, ActivityKit und WidgetKit.

Der naive Weg wäre ein einziger universeller TimerManager mit #if-Verzweigungen für jeden Plattformunterschied. Den habe ich nicht gewählt. Return enthält drei Timer-Klassen (TimerManager auf iOS und macOS, TVTimerManager auf tvOS, WatchTimerManager auf watchOS), die dieselbe Zustandssemantik teilen, aber respektieren, worin jede Plattform tatsächlich gut ist. Live Activities nur auf iOS. HealthKit nur dort, wo die API existiert. Extended Runtime Sessions nur auf der Watch. Jeder Manager ist kürzer und ehrlicher, als eine einzelne polymorphe Klasse es wäre.

Return auf dem iPhone 17 Pro Max mit dem Feuer-Thema
iPhone
Return auf macOS mit dem Feuer-Thema
Mac
Return auf der Apple Watch Series 11 mit dem Feuer-Thema
Watch
Return auf dem Apple TV mit dem Feuer-Thema
Apple TV
Return auf dem iPad Pro 13 Zoll mit dem Feuer-Thema
iPad

Geteilt, wo es zählt.

Ein einziger Shared/-Ordner trägt die Teile, auf die sich alle Targets einigen müssen: das Datenmodell MeditationSession, den iCloud-Wrapper SessionStore und SessionHistoryView. Einstellungen werden zwischen Watch und iPhone über eine App Group (group.com.941apps.Return) synchronisiert. Der Rest ist bewusst plattformspezifisch.

Das deutlichste Beispiel ist die eine Zeile, die entscheidet, ob eine Sitzung bereits in HealthKit protokolliert wurde. Das iPhone schreibt direkt, also ist „synced“ in dem Moment wahr, in dem die Sitzung endet. Mac und TV können überhaupt nicht in HealthKit schreiben, also ist „synced“ falsch, bis das iPhone die anstehende Sitzung später aufnimmt. Dieselbe Absicht, entgegengesetzter Boolean, ein #if:

Swift · TimerManager.swift:120-138
/// Save session to SessionStore for cross-device sync and HealthKit syncing
private func saveSessionToStore(startTime: Date, endTime: Date) {
    // On iOS: if healthKitEnabled, we save directly to HealthKit, so mark as synced
    // On Mac: if healthKitEnabled, we want to sync to iPhone, so mark as NOT synced
    #if os(iOS)
    let alreadySynced = settings.healthKitEnabled
    #else
    let alreadySynced = !settings.healthKitEnabled
    #endif

    let session = MeditationSession(
        startDate: startTime,
        endDate: endTime,
        sourceDevice: .current,
        syncedToHealthKit: alreadySynced
    )

    SessionStore.shared.addSession(session)
}

Zu diesem Muster komme ich immer wieder zurück: die wenigsten Zeilen, die die Absicht noch lesbar machen. Wenn derselbe Boolean auf verschiedenen Plattformen unterschiedliche Dinge bedeutet, schreib ihn als unterschiedliche Booleans. Das #if wird Teil der Dokumentation.

Lokalisiert

Siebenundzwanzig Sprachen und Unterstützung für Rechts-nach-links.

Return ist die erste Apple-App, die ich in jeder Sprache veröffentlicht habe, die mir wichtig war. Siebenundzwanzig Locales haben einen vollständigen Review-Durchlauf durchlaufen, einschließlich Arabisch und Hebräisch. Das alles liegt in einer einzigen Localizable.xcstrings-Datei, was weniger heldenhaft ist, als es klingt. Xcode erledigt den Großteil der Arbeit, wenn man aufhört, Strings von Hand zu basteln.

Return-Startbildschirm, Wasser-Thema, Englisch
EnglishStart · Wasser
Return-Startbildschirm, Feuer-Thema, Japanisch
日本語Start · Feuer
Return-Startbildschirm, Wald-Thema, Vereinfachtes Chinesisch
简体中文Start · Wald
Return-Einstellungsbildschirm, Deutsch
DeutschEinstellungen
Return HealthKit-Berechtigungsbildschirm, Koreanisch
한국어HealthKit

RTL ist ein kostenloser Gewinn, wenn man aufhört, dagegen anzukämpfen.

SwiftUI behandelt .leading und .trailing als semantische Richtungen, nicht .left und .right als feste. Wenn man einen Bildschirm einmal in semantischen Richtungen anlegt, spiegelt sich derselbe Bildschirm automatisch auf Arabisch, Hebräisch, Persisch oder Urdu, ohne einen eigenen Code-Pfad. Beschriftungen in den Einstellungen kippen, das Zurück-Chevron dreht sich um, Schalterpositionen werden invertiert. Themen-Icons (Tropfen, Flamme, Blatt) bleiben, wo sie sind. Ich habe für dieses Verhalten keine Zeile RTL-Code geschrieben.

Return-Startbildschirm, Wald-Thema, Englisch, Links-nach-rechts-Layout
Englisch · LTR
Return-Startbildschirm, Wald-Thema, Arabisch, Rechts-nach-links-Layout
Arabisch · RTL
Return-Startbildschirm, Wald-Thema, Hebräisch, Rechts-nach-links-Layout
Hebräisch · RTL

Eine Ausnahme, die mir beim Release aufgefallen ist: SwiftUI wendet die Layout-Richtung auch auf Text-Views an, was dazu führte, dass der erste Schnitt der arabischen und hebräischen Screenshots den Timer als „00:02“ statt „20:00“ zeigte — lateinische Ziffern von rechts nach links gelayoutet. Ein einziger .environment(\.layoutDirection, .leftToRight)-Modifikator auf jeder Text-View, die Zeit- oder Zahleninhalte enthält, behebt das. Die Screenshots oben stammen aus dem Release, der genau diesen Modifikator eingebaut mitbringt.

Der Screenshot-Satz wurde von fastlane erzeugt, das dieselben UI-Tests mit unterschiedlichen -AppleLanguages-Argumenten ausführt. Das app-eigene effectiveLocale-Muster liest das Flag, baut die View-Hierarchie neu auf und erfasst das Ergebnis. Ein Helfer, siebenundzwanzig Locales, vier Geräteklassen — alles in einem einzigen Lauf über Nacht.

Swift · ReturnWatchApp.swift:92-111
/// The locale to use for the app - either user-selected or system default
/// In snapshot mode, always use system language (set by -AppleLanguages)
/// to allow screenshot generation for different locales
private var effectiveLocale: Locale {
    if isSnapshotMode || appLanguage.isEmpty {
        if let preferredLanguage = Locale.preferredLanguages.first {
            return Locale(identifier: preferredLanguage)
        }
        return .current
    }
    return Locale(identifier: appLanguage)
}

var body: some Scene {
    WindowGroup {
        WatchContentView()
            .preferredColorScheme(.dark)
            .environment(\.locale, effectiveLocale)
            .id(appLanguage) // Force rebuild when locale changes
    }
}

Das .id(appLanguage) ist das Detail, das seinen Platz verdient. Ohne das cached SwiftUI die alte View-Hierarchie, und die Strings aktualisieren sich nicht, wenn man zur Laufzeit die Sprache wechselt. Mit ihm wird der gesamte Baum verworfen und neu aufgebaut, und alles liest seine lokalisierten Strings automatisch neu. Eine Zeile, eine ganze Kategorie von Bugs gelöscht.

HealthKit

Endlich Achtsamkeitsminuten.

Apples native Watch-App „Achtsamkeit“ deckelt die eingebauten Reflektions- und Atemsitzungen bei fünf Minuten. Die HealthKit-API selbst hat keine solche Obergrenze. Sie akzeptiert bereitwillig jede HKCategorySample, bei der das Enddatum nach dem Startdatum liegt. Die Grenze liegt im UI, nicht im System. Return stellt auf jedem Gerät einen Auswähler von 5 bis 60 Minuten bereit und schreibt das, was du tatsächlich gesessen hast.

Swift · HealthKitManager.swift:92-103
/// Save a mindful session with the given start and end time
func saveMindfulSession(start: Date, end: Date) async -> Bool {
    guard isAvailable else { return false }

    // Don't save if end is before or equal to start
    guard end > start else { return false }

    let sample = HKCategorySample(
        type: mindfulType,
        value: HKCategoryValue.notApplicable.rawValue,
        start: start,
        end: end
    )
    ...
}

Die einzige Validierung lautet end > start. Genau das validiert HealthKit selbst. Apples API war schon immer bereit, eine fünfundvierzigminütige Meditation zu protokollieren. Es fehlte lediglich der Knopf, eine anzufordern.

Geräteübergreifend, obwohl drei davon kein HealthKit haben.

Mac und Apple TV haben überhaupt kein HealthKit. Die naheliegende Reaktion ist: „Dann protokolliere dort eben keine Sitzungen.“ Die weniger naheliegende, richtige Reaktion ist, sie trotzdem zu protokollieren, in den iCloud Key-Value Store, und sie vom iPhone aufnehmen zu lassen, wenn es das nächste Mal aufwacht. Returns SessionStore ist der gemeinsame Speicher, MeditationSession.syncedToHealthKit ist das Ausstehend-Flag, und HealthKitManager.syncPendingSessions() läuft jedes Mal, wenn die iOS-App in den Vordergrund zurückkehrt.

SessionStore
iCloud Key-Value Store
Ausstehende Sitzungen
iPhone schreibt in HealthKit ♥
Balkendiagramm der Apple-Health-Achtsamkeitsminuten, das einen Durchschnitt von 20 Minuten über einen Monat zeigt
Apple Health Achtsamkeitsminuten, Balkenansicht. Apples eigene Achtsamkeits-App ist bei einer fünfminütigen Reflektionssitzung am Ende. Dem zugrundeliegenden Speicher ist es egal, was man hineinschreibt.
Kalenderansicht der Apple-Health-Achtsamkeitsminuten, die 18 Praxistage in den vergangenen 4 Wochen zeigt
Dieselben Daten, Kalenderansicht: 18 Tage in den vergangenen 4 Wochen, jede Sitzung aus Return protokolliert.
Return-Sitzungsverlauf-Bildschirm, der eine Liste 20-minütiger Meditationssitzungen zeigt
Returns eigener Sitzungsverlauf. Jedes Gerät steuert etwas bei, und jede Sitzung trägt einen Quellen-Marker.

Das ist das Stück, von dem ich finde, dass Apple es selbst liefern sollte: einen ordentlichen plattformübergreifenden Achtsamkeitsminuten-Writer, der kein aktives Telefon voraussetzt, nur weil man auf einem Mac meditieren will. Bis sie das tun, tut Return es.

Generativ

Woher das Wasser kam.

Vier Themen. Vier Ambient-Loops. Drei Glocken. Alles generiert, das meiste davon weggeworfen. Die Videos stammen aus Midjourney, das Audio aus ElevenLabs, und die Arbeit, auf die es ankam, war nicht das Prompting. Es war das Editieren. Ein Raster aus zweihundert Wassertropfen ansehen und den einen heraussuchen, der sauber ohne sichtbare Naht loopt. Vierzig Variationen einer Tempelglocke hören, bis eine den richtigen Anschlag und das richtige Ausklingen hat und nicht wie eine Telefonbenachrichtigung klingt.

Midjourney-Kontaktbogen: Hunderte Wassertropfen-Varianten, einige mit Herzen und Abspiel-Dreiecken markiert
Wasser · 128 gezeigt
Midjourney-Kontaktbogen: Dutzende Feuer-Varianten
Feuer · 96 gezeigt
Midjourney-Kontaktbogen: Baumkronen- und Blattvarianten
Wald · 60 gezeigt
Midjourney-Kontaktbogen: Wolken- und Himmelserkundungen, die nicht ins Produkt gingen
Unveröffentlichte Erkundung · 128 gezeigt

Jede Kachel ist eine Generierung. Die Herzen sind diejenigen, die den ersten Durchgang überlebt haben. Die Abspiel-Dreiecke sind die, die ich ins Video überführt habe. Vier Themen sind veröffentlicht. Alles andere blieb im Raster, und genau darum geht es im Prozess: Das Verhältnis zählt.

Die Glocken folgten im Audio demselben Bogen. Prompten, hören, verfeinern, erneut prompten. Drei habe ich behalten: Singing Bowl, Temple Bell, Soft Chime. Jede iteriert, bis sie aufhörte, synthetisch zu klingen.

Ich werde nicht so tun, als würde ich die Gesamtzahl der Generierungen zählen. Hunderte pro Thema ist eine ehrliche Schätzung. Die Disziplin liegt nicht im Prompting. Sie liegt darin, alles wegzuwerfen, was bloß gut ist, und nur das zu behalten, was zwanzig stille Minuten hinter einem Timer sitzen kann, ohne jemals das zu werden, was man bemerkt.

Praxis

Warum ein Timer, kein Lehrer.

Dieser Teil ist persönlich. Ich habe Return gebaut, weil ich bereits eine Meditationspraxis habe und keinen Timer finden konnte, der mir aus dem Weg geht. Worin ich sitze, ist japanisches Zen in seiner kriegerischen Strömung: Takuan, Yagyu, Musashi, Dogen, Hakuin. Nicht die therapeutische Achtsamkeit, wie sie die großen Apps liefern. Andere Absicht, andere Textur.

Was in einer beliebigen Woche rotiert:

  • Susokukan (Atemzählen). Beim Atem von eins bis zehn zählen, zur Eins zurückkehren, sobald die Zählung verloren geht. Fundament. Konzentration, joriki, zuerst.
  • Shikantaza (einfach nur sitzen). Objektlos. Kein Zählen, keine Frage, keine Visualisierung. Der Geist, der sich nicht festmacht. Dogens zentrale Form des zazen und die formale Annäherung, die dem Zustand, den ich tatsächlich will, am nächsten kommt.
  • Koan. Vor allem Joshus Mu. Eine Frage, die sich nicht durch Denken lösen lässt, gehalten, bis das Denken aufgibt.
  • Maranasati (Todesbetrachtung). Hagakure-Rahmung. Sparsam verwendet. Überleben spannt den Geist an; das schneidet hindurch.
  • Isshin (ein Geist). Takuans und Yagyus Terrain: entspannt, aber engagiert, gefestigt, aber beweglich. Die Brücke zwischen dem Kissen und dem, was danach kommt.
  • Integrationstage. Dankbarkeit, Mitgefühl, Linie. Jihi. Katsujinken: das lebensspendende Schwert, nicht das tötende Schwert. Meistens samstags.
  • Sakki (Bewusstsein feindseliger Absicht). An jede Sitzung werden fünf Minuten offenes Zuhören im freien Feld angehängt. Das holt shikantaza vom Kissen und testet es in gewöhnlichen Umgebungen unter Druck.

Die Rotation ist nicht starr. Atemzählen, wenn ich mich stabilisieren muss. Koan, wenn ich durchbrechen muss. Shikantaza, wenn ich in Offenheit ruhen muss. Todesbetrachtung, wenn der Einsatz geklärt werden muss. Die Vielfalt gehört zum Training.

Return ist ein Timer, weil ich auf meinem Telefon keinen Lehrer brauche. Ich brauche etwas, das die Uhr hält, damit ich es nicht muss, das Anfang und Ende mit einer Glocke markiert, die ich respektiere, und sich dazwischen aus dem Weg hält. Wenn du bereits eine Praxis hast, ist das wahrscheinlich auch das, was du willst. Wenn du ganz neu bist, such einen Lehrer in einem Raum. Dann komm zurück.

Zurückhaltung

Was nicht in Return ist.

Return ist nicht Calm. Es ist nicht Headspace. Da ist kein britischer Erzähler, der dich sanft in einen Body-Scan einführt. Da ist kein Comic-Avatar, der deine Streak feiert. Da ist kein Abo, das neue geführte Programme freischaltet. Return ist ein Timer. Die Idee ist: Wenn du bereits eine Praxis hast, brauchst du keinen Lehrer in der App. Du brauchst ein Werkzeug, das die Zeit für dich hält und aus dem Weg geht.

  • Keine geführte Stimme, keine Erzählung
  • Keine Streaks, Punkte oder Gamification
  • Kein Abo, keine In-App-Käufe
  • Niemals Werbung
  • Keine Analytics; die App trackt nichts
  • Kein Social-Login, kein Teilen
  • Keine Nerv-Screens, keine Cold-Start-Modals
  • Keine Dark Patterns im IAP-Flow, weil es keinen IAP-Flow gibt

Was bewusst klein gehalten in Return steckt: vier Wiederholungsmodi (Einmal, Bis gestoppt, Bis Zeit, N-mal wiederholen), eine zweisekündige Atempause zwischen Zyklen, ein bis drei Glockenschläge bei jedem Übergang, eine Auswahl aus drei Glocken, vier Themen, HealthKit-Opt-in und eine Sprachauswahl. Das ist das gesamte Produkt.

Der Preis dieser Strenge zeigt sich im Einstellungsmodell. Jede benutzerseitige Einstellung wird von der Property selbst auf einen gültigen Bereich begrenzt, nicht von der UI-Validierung. UI-Validierung ist ein weiteres Dark Pattern, wenn man nicht aufpasst. Der bellRepeatCount-Getter kann nichts anderes als 1, 2 oder 3 zurückgeben. Schreibt man 0 oder 47 in das darunterliegende @AppStorage, wird stillschweigend auf den zulässigen Bereich geklemmt.

Swift · Settings.swift:74-81
@ObservationIgnored
@AppStorage("bellRepeatCount") private var _bellRepeatCount = 1

/// Validated bell repeat count (1-3)
var bellRepeatCount: Int {
    get { max(1, min(3, _bellRepeatCount)) }
    set { _bellRepeatCount = max(1, min(3, newValue)) }
}

Return kostet 2,99 $. Man bezahlt einmal und besitzt es. Keine Serverkosten zu stützen, kein Abo zu verlängern, keine Analytics-Pipeline, die zusieht, was du tust. Das Produkt ist das Produkt. Wenn du die längere Version davon willst, warum ich Apps so baue, lies Minimum Worthy Product und The Steve Test. Die kurze Version steht in diesem Abschnitt.

Return.

Jetzt im App Store verfügbar für iPhone, iPad, Apple Watch, Apple TV und Mac.