Commit Graph
91 Commits
Author SHA1 Message Date
ScarriffleandClaude Opus 5 e3b215a1dd Ein eigener Sperrbildschirm — und ohne gespeichertes Passwort
Kameraaufnahme, Anlernen über drei Posen, Fenster je Bildschirm auf
Bildschirmschoner-Ebene, Passwortrückfall.

**Das Anmeldepasswort wird nicht gespeichert.** Ein Spike hat den Weg
freigeräumt: `ODRecord.verifyPassword` ist öffentliche API, die Eingabe geht
direkt hinein, das Ergebnis ist ein `Bool`, danach ist die Zeichenkette wieder
weg. Damit fällt der Grund weg, aus dem vergleichbare Programme sich das
Passwort geben lassen und in die Keychain legen.

Angelernt wird über drei Posen mit je fünf Aufnahmen. Der Merkmalsvektor ist ein
allgemeiner Bildmerkmalsvektor und kein Gesichtsmerkmal — er reagiert auf
Kopfhaltung und Beleuchtung mit. Eine einzige Aufnahme beschreibt genau eine
Haltung bei genau einem Licht.

Die Vektoren liegen in der Keychain, nicht in einer Datei: aus ihnen lässt sich
kein Bild zurückgewinnen, aber wer sie hat, kann prüfen, ob eine bestimmte
Person vor der Kamera stand.

Die Einschränkung steht auf dem Sperrbildschirm selbst und nicht im
Kleingedruckten: Bequemlichkeit, keine Sicherheitsgrenze; der Vergleich läuft
über die Webcam und lässt sich mit einem Foto täuschen. Wer sich darauf
verlässt, tut es dort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:22:32 +02:00
ScarriffleandClaude Opus 5 3da673662f Zwischenablage, Notizen und der Gesichtsvergleich
Drei neue Module nach dem Bauplan von `ShelfProvider`: reine Regeln getrennt vom
Zustand, versionierte Indexdatei, Inhalte in Dateien statt in `UserDefaults` —
was dort steht, liest jedes Programm mit `defaults read` mit.

Die Zwischenablage achtet `ConcealedType`, `TransientType` und
`AutoGeneratedType`. Diese Marken sind eine Verabredung zwischen Programmen und
kein Systemdienst; wer sie missachtet, sammelt fremde Passwörter ein.

Der Gesichtsvergleich stand im Plan als der eine echte Unsicherheitsfaktor. Ein
Spike hat ihn erledigt: `VNGenerateFaceprintRequest` gibt es nicht, aber
`VNGenerateImageFeaturePrintRequest` ist öffentlich, liefert 768 Elemente und
ein Abstandsmaß — Faktor 3,5 Trennschärfe. Kein eigenes CoreML-Modell nötig.

`FaceMatcher` entscheidet über mehrere Posen, mehrere Einzelbilder und eine
Sperre nach Fehlversuchen. Die Schwelle liegt bewusst nicht mittig: ein falsches
Ja ist ein Fremder am entsperrten Rechner, ein falsches Nein nur ein Passwort,
das man ohnehin kennt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:06:06 +02:00
ScarriffleandClaude Opus 5 f289d02c37 Der Akku bekommt ein Gedächtnis
Verlauf über 24 Stunden, sieben Tage und dreißig Tage, aufgezeichnet alle fünf
Minuten. Als Säulen und nicht als Linie: eine Linie verbindet auch dort, wo
nichts gemessen wurde, und ein zugeklappter Rechner hatte keinen Ladestand —
eine Linie darüber behauptet einen.

Dazu Segelmodus und Hitzeschutz als reine Regeln im Helfer. Beide haben zwei
Schwellen, eine zum Anhalten und eine zum Weitermachen. Ohne diesen Abstand
hinge der Akku am Limit und würde bei jedem verlorenen Prozent nachgeladen —
hunderte winzige Ladevorgänge am Tag, und genau die altern ihn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:06:06 +02:00
ScarriffleandClaude Opus 5 edb327cabe Kacheln und Fenster sprechen dieselbe Sprache
Alle Kacheln, Popovers und Fenster auf die Designschicht umgestellt: rund
hundert gesetzte Schriftgrößen und 159 gesetzte Abstände und Radien sind jetzt
Token. Übrig bleibt `spacing: 0` — das ist eine Aussage, keine geratene Zahl.

Die Einstellungen bekommen eine Seitenleiste statt sieben Reitern, deren
deutsche Beschriftungen zusammen 880 Punkte brauchten. Panel-Token stehen nicht
mehr in Fenstern: dort gilt Systemsemantik, damit der Hellmodus nicht schwarz
auf schwarz endet.

Neu ist ein Schaufenster, das alle Bauteile nebeneinander zeigt — ohne das
lässt sich eine Änderung an einem Token nur prüfen, indem man die App bedient,
bis jede Kachel einmal zu sehen war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:05:51 +02:00
ScarriffleandClaude Opus 5 9b600de9a9 Live Activities unter der Notch, nicht daneben
Neben ihr wären die Arme zwangsläufig gleich breit — die Silhouette zeichnet den
Steg mittig um die Hardware. Ein Symbol links und ein Balken rechts hieße dann
132 Punkte Schwarz für ein Symbol. Darunter hängt die Fläche frei und wird so
breit, wie ihr Inhalt es braucht.

Lautstärke, Strom, Titelwechsel und Helligkeit. Gemeldet wird nur, was sich
**geändert** hat: `PowerWatcher` schweigt beim ersten gelesenen Zustand, sonst
begrüßte Onyx jeden Start mit „am Netz".

Die Helligkeit kostete einen Spike. Von drei Wegen trägt nur `DisplayServices`,
und nur für den eingebauten Bildschirm. `CoreDisplay` — der Weg, den jede
Anleitung empfiehlt — gibt für alle Bildschirme 1.0 zurück, auch für den, der
auf 62 % stand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:05:13 +02:00
ScarriffleandClaude Opus 5 c05ccb8ae1 Die Notch wird zur Insel, wo es keine Hardware gibt
Die Silhouette bestand aus zwei überlappenden Teilpfaden. Gefüllt stimmte die
Vereinigung, aber die Kontur zeichnete jeden Teilpfad vollständig nach — auch
dort, wo er innen lag. Dazu kippte die Form ab einer Breite in einen anderen
Zweig, und die beiden Zweige waren nicht dieselbe Geometrie. Zusammen war das
das Flackern an den Rundungen. Jetzt ein durchgehender Umriss, dessen Zweige
ineinander übergehen statt zu springen.

Neu ist die Wahl zwischen verschmolzen und schwebend. Eine echte Notch **muss**
an der Kante kleben und oben eckig sein, sonst klafft ein Spalt zum Gehäuse;
eine Insel **muss** Abstand halten und rundum gerundet sein, sonst sieht sie aus
wie ein abgeschnittenes Rechteck. Beides zu mischen geht nicht, deshalb eine
Wahl und keine zwei Schalter.

Ihre Höhe rät Onyx nicht mehr, sondern misst die Menüleiste: 24 Punkte minus
Luft oben und unten. Vorher hing ein festes Maß unten heraus.

Dazu „nur der Hauptbildschirm" als dritte Anzeigewahl — gemeint ist der mit der
Menüleiste, nicht `NSScreen.main`, das mit dem aktiven Fenster mitwandert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:05:13 +02:00
ScarriffleandClaude Opus 5 ecb39fbe5f Eine Designschicht statt hundertfach gesetzter Zahlen
Token für Schrift, Symbolgröße, Abstand, Radius und Bewegung, dazu sieben
Bauteile, die vorher in jeder Kachel neu gebaut wurden — Karte, Abschnittstitel,
Hinweis, Pillenknopf, Regler, Ablegefläche, Haarlinie.

Symbole bekommen eine **eigene** Staffel und nicht die der Schrift: ein
9-Punkt-Symbol neben 9-Punkt-Text wirkt kleiner, nicht gleich groß. Beide in
eine Staffel zu zwingen hieße, an jeder Stelle gegen sie zu arbeiten.

Das Flächenrezept — Tint, Bänderung, Kante — stand zweimal da, einmal für das
Panel und einmal für Fenster. Es ist jetzt `OnyxStone`, generisch über die Form,
damit auch die animierende Notch-Silhouette es benutzen kann.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:04:51 +02:00
ScarriffleandClaude Opus 5 49a3ff0548 Panel je Bildschirm messen, nicht am schmalsten
Die Breite kam vom **schmalsten** aktiven Bildschirm — mit der Begründung,
dasselbe Panel erscheine überall. Ein Fernseher widerlegt das: bei 720 Punkten
Breite bleiben drei Spalten, vier Widgets brechen auf zwei Reihen um, und das
Panel wird hoch statt breit. Auf dem Notebook, wo achtmal Platz gewesen wäre.

Jetzt rechnet jeder Bildschirm für sich. Der Koordinator kennt seine
Bildschirme ohnehin und reicht die Kennung schon durch — sie wurde nur nicht
benutzt.

Die zweite Hälfte war, dass es nach dem Abstecken so blieb: die Größe wurde
einmal gerechnet und nie wieder. `NSScreen` meldet sich nicht bei SwiftUI,
also gibt es jetzt einen mitgezählten Bildschirmwechsel, den die Ansicht
mitliest, und beim Wechsel werden die Fenstergrößen neu gesetzt — verzögert um
einen Durchlauf, damit der Koordinator seine Fenster vorher neu aufgebaut hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:59:46 +02:00
ScarriffleandClaude Opus 5 286d886e9e Das Mikrofon nur noch auf Knopfdruck
Ein offener Eingangsstrom ist bei Bluetooth-Hörern kein stiller Mitleser.
Gemessen an AirPods Pro:

  vorher    48000 Hz, Gerätelautstärke 0.0
  mit Mikro 24000 Hz, Gerätelautstärke 0.6
  danach    48000 Hz, Gerätelautstärke 0.0

macOS schaltet sie ins Telefonprofil: halbe Abtastrate, und der
Lautstärkeregler des Geräts springt. Die Musik wird hörbar lauter und
schlechter — beim Öffnen des Popovers, und beim Schließen wieder zurück.
Dasselbe passiert, wenn am Telefon eine App das Mikrofon greift.

Das darf nicht passieren, weil jemand ein Lautstärkefenster aufmacht. Der
Mikrofonpegel hängt deshalb an einem Knopf in der Eingabezeile, mit dem
Hinweis im Tooltip, was er auslöst. Beim Schließen des Popovers geht er in
jedem Fall wieder aus.

Der Ausgangspegel bleibt automatisch: der läuft über einen Process Tap und
fasst das Gerät nicht an.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:32:19 +02:00
ScarriffleandClaude Opus 5 4dee12e4b9 Das Wetter sah nur einmal je Programmstart nach
Der Abruf hing an `task` der View — und die erscheint bei einem Panel, das
immer existiert, ein einziges Mal. Wer Onyx tagelang laufen lässt, sieht
tagelang dieselbe Temperatur. Gemessen: der Zwischenspeicher trug den Stand
vom 14. August, 15:17, und stand am 17. um 23:13 unverändert da — nachts
35 Grad, weil sie vom Nachmittag drei Tage vorher stammten.

Jetzt sieht das Modell im Takt der Haltbarkeit nach, also alle fünfzehn
Minuten. Teurer wird es dadurch nicht: `load` fragt nur nach, wenn der
gespeicherte Stand abgelaufen ist. Und der Ort wird dabei neu bestimmt — beim
Wechsel der Stadt stand sonst weiter das Wetter der alten da. Genau das war
hier zu sehen: Lemgo, längst verlassen.

Dazu die zweite Hälfte des Fehlers: ein „fertiger" Stand wurde immer als
frisch gezeichnet, egal wie alt er war. Warnzeichen und Zeitstempel gab es nur
bei einem gescheiterten Abruf. Ein Messwert gilt jetzt ab einer Stunde als
alt — großzügiger als die Haltbarkeit, damit ein einzelner verpasster Abruf
noch keine Warnung auslöst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 23:23:50 +02:00
ScarriffleandClaude Opus 5 ee848b86cc Das Aufnahmesymbol kam vom Mixer, nicht vom Pegel
Gemessen über kAudioProcessPropertyIsRunningInput: mit laufendem Mixer nimmt
Onyx auf, ohne ihn nicht. Ein Process Tap ist für macOS eine Tonaufnahme —
auch wenn damit nur die Lautstärke geregelt wird. Solange der Mixer Chrome und
Firefox abgreift, steht das orange Symbol in der Leiste.

Der Mixer stand seit der Fehlersuche am Wochenende auf „automatisch starten",
deshalb war es dauerhaft. Das Häkchen steht jetzt wieder aus.

Ein Hinweis unter dem Häkchen sagt das jetzt, wo die Entscheidung fällt: wer
das Symbol ohne Erklärung sieht, sucht den Fehler bei sich oder hält die App
für unsauber.

Dazu ein echter Fund an derselben Stelle: der Mikrofonpegel hing an
`onDisappear` der View — und das bleibt bei einem NSPopover aus. Dessen
Controller lebt nach dem Schließen weiter, die View verschwindet nie aus der
Hierarchie. Die Messung wäre also beim ersten Öffnen angegangen und nie wieder
aus. Sie hängt jetzt am Popover selbst: `MenuBarModule` bekommt
`popoverDidOpen`/`popoverDidClose`, gemeldet auch dann, wenn das Popover von
selbst zugeht — beim Wechsel in eine andere App etwa.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 15:20:07 +02:00
ScarriffleandClaude Opus 5 9975694d6a Terminliste: an welchem Tag denn?
Zweimal „Nina arbeiten, 8:00" untereinander sind zwei verschiedene Tage, und
nichts verriet welche. Die Uhrzeit beantwortet nur die halbe Frage.

Jetzt steht über jedem Tag eine Überschrift: „Heute", „Morgen", danach
Wochentag und Datum. Die Wörter für die nächsten beiden Tage, weil sie kürzer
sind als jedes Datum und sofort beantworten, was man wissen will. Der
Wochentag allein wäre in drei Wochen mehrdeutig, deshalb steht das Datum
dabei.

Ganztägige Termine stehen jetzt über den Uhrzeiten desselben Tages. Sie
beginnen um Mitternacht und standen deshalb zwischen den frühen Terminen —
dabei gelten sie für den ganzen Tag.

Die Entscheidung „heute/morgen/später" liegt getrennt von ihrer Beschriftung,
damit sie ohne Sprachkatalog prüfbar bleibt: im Testlauf steht sonst der rohe
Schlüssel statt des Wortes, und der Test prüft die Übersetzung statt der
Logik.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 13:52:16 +02:00
ScarriffleandClaude Opus 5 0df566d531 Symbole folgen der Akzentfarbe, nicht der des Systems
SwiftUI zeichnet Symbole in Listen und Formularen auf macOS in der
Akzentfarbe des Systems — nicht in der des Fensters. `.tint` an der Wurzel
half deshalb nur der Reiterleiste; die Widget-Liste blieb systemgrün neben
einer blauen Leiste, obwohl beides derselben Einstellung folgen soll.

Ein eigener Label-Stil setzt die Farbe am Symbol. Er vererbt sich über die
Umgebung, also genügt eine Zeile an denselben vier Wurzeln, an denen auch der
Farbton gesetzt wird: Panel, Popovers, Einstellungen, Einrichtung.

Ein Symbol, das seine Farbe selbst mitbringt, behält sie — die innere Angabe
schlägt die äußere. Der grüne Haken für „erteilt" bringt sie jetzt am Symbol
mit statt am ganzen Label: Grün heißt dort „erteilt" und ist keine
Geschmacksfrage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 13:48:57 +02:00
ScarriffleandClaude Opus 5 fde3e864c0 Zwei-Faktor-Anmeldung bei Calendarr
Deine Zugangsdaten stimmten. Der Fehler lag im gewählten Endpunkt:

  auth_router.py:81   if user.totp_enabled:
                          raise HTTPException(401, detail="2fa_required")

/api/auth/token nimmt nur ein Formular mit Benutzername und Passwort entgegen
und weist Konten mit zweitem Faktor grundsätzlich ab — mit demselben 401 wie
ein falsches Passwort. Deshalb stand da „Benutzername oder Passwort stimmen
nicht", obwohl beides stimmte.

Angemeldet wird jetzt über /api/auth/login: der Weg nimmt den Code entgegen
und kennt remember_me. Das ist hier keine Bequemlichkeit, sondern die
Bedingung — mit zweitem Faktor kann Onyx sich nicht selbst neu anmelden, den
Code hat nur der Mensch. Ein gewöhnliches Token hielte sieben Tage,
remember_me hält hundertachtzig.

Damit wandert auch das Token in den Schlüsselbund. Bei einem Konto mit
zweitem Faktor ist es das einzige, womit Onyx noch hineinkommt; ginge es beim
Beenden verloren, müsste man sich bei jedem Start neu anmelden.

Die drei Fälle sind jetzt auseinandergehalten und einzeln beschriftet:
falsches Passwort, fehlender Code, falscher Code. Der Unterschied ist der
zwischen „Passwort neu tippen" und „App aufmachen" — und er steckt beim
Server nur im Begleittext eines 401.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 13:44:26 +02:00
ScarriffleandClaude Opus 5 e2b86c0216 Calendarr direkt vom Server
Bisher las Onyx nur den Schnappschuss aus dem gemeinsamen Ordner. Der ist so
aktuell wie der letzte Start der Calendarr-App — wer sie eine Woche nicht
öffnet, sieht wochenalte Termine, und Onyx kann nichts dafür und nichts
dagegen. Der Live-Weg stand im Plan als „bewusst weggelassen, später ohne
Umbau nachrüstbar". Das stimmte: das Quellenprotokoll hat gehalten.

Ein einziger Aufruf genügt. /api/caldav/events fasst CalDAV-Konten, lokale
Kalender, Geburtstage, iCal-Abos und Google bereits zusammen — nachgebaut wird
nichts.

Angemeldet wird mit Adresse, Benutzername und Passwort statt mit einem Token,
und der Grund steht im Backend:

  auth.py:17   ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7   # 7 days

Ein eingetragenes Token wäre nach einer Woche tot. Onyx holt sich seines
deshalb selbst und erneuert es, bevor es abläuft — die Gültigkeit liest es aus
dem Token, statt sieben Tage anzunehmen; die stehen heute so im Server und
morgen vielleicht nicht mehr. Kommt trotzdem ein 401, wird einmal neu
angemeldet und der Abruf wiederholt.

Adresse und Benutzername stehen in den Einstellungen, das Passwort im
Schlüsselbund — `defaults read` ist keine Stelle, an der ein Passwort
mitgelesen werden soll. Geprüft wird beim Verbinden, nicht erst beim nächsten
Laden: ein Tippfehler, den man am Folgetag bemerkt, ist ein vermeidbarer.

Der Schnappschuss bleibt das Netz darunter. Ohne Zugangsdaten ändert sich
nichts, und ohne Netzwerk hält er, was Calendarr zuletzt geschrieben hat.
Nachgesehen wird am Server alle fünf Minuten statt alle zwei: ein Dateizugriff
kostet nichts, eine Anfrage über das Netz schon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 13:34:57 +02:00
ScarriffleandClaude Opus 5 c8f3054036 Calendarr: ein Blick alle zwei Minuten unter die Benachrichtigung
Onyx holt sich nichts, sondern liest den Schnappschuss, den Calendarr in den
gemeinsamen Ordner schreibt — kein Netzzugriff, kein zweiter Zwischenspeicher.
Gemeldet wird das über eine Darwin-Nachricht, und darauf hört Onyx.

Die Nachricht ist aber flüchtig: schreibt Calendarr, während Onyx nicht läuft
oder gerade startet, kommt sie nie an. Der Schnappschuss steht dann so lange
still, bis Calendarr das nächste Mal schreibt — und die Terminliste ist aus
unerfindlichen Gründen von gestern.

Also zusätzlich alle zwei Minuten nachsehen, solange Calendarr überhaupt
gefragt wird. Das kostet das Einlesen einer Datei von vierzehn Kilobyte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 13:15:58 +02:00
ScarriffleandClaude Opus 5 d90352a86b DMG für den eigenen Rechner
Der App Store ist für Onyx kein Weg: er verlangt die Sandbox, und ohne die
gäbe es keinen privilegierten Helfer, keinen IOKit-Zugriff, keine
Audio-Taps — also weder Lüftersteuerung noch Ladelimit, Hardwaremesswerte
oder Mixer. Das steht so in der Planung, war aber nie als Skript hinterlegt,
das man ohne Zertifikatsantrag laufen lassen kann.

Scripts/local-dmg.sh füllt die Lücke: Release-Build mit dem
Entwicklerzertifikat, dieselben drei Prüfungen wie beim Verteilen —
Signatur, App-Group, Kennung des Helfers — und ein DMG mit Verweis auf den
Programme-Ordner.

Der Unterschied zu release.sh ist nicht die Verpackung, sondern die
Signatur. Auf dem Mac, auf dem das Zertifikat zuhause ist, läuft es; auf
einem fremden meldet Gatekeeper einen unbekannten Entwickler. Für die
Weitergabe bleibt es bei Developer ID und Notarisierung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 12:52:17 +02:00
ScarriffleandClaude Opus 5 c6f0a5a848 Vorschau liest macOS' eigene Hintergrundverwaltung
NSWorkspace.desktopImageURL ist die alte Schnittstelle: sie meldet das letzte
Bild, das als Datei gesetzt wurde — auch dann noch, wenn es längst gelöscht
ist. Genau das war hier der Fall, der Pfad zeigt auf eine Datei, die es nicht
mehr gibt. Seit macOS 14 führt das System die Auswahl in
com.apple.wallpaper/Store/Index.plist, je Bildschirm und je Schreibtisch, und
Anbieter wie Fotos hinterlegen dort ihre Zwischenspeicher.

Die Datei ist doppelt verpackt: die Konfiguration je Bildschirm steckt als
eigene Property-Liste in einem Datenfeld der äußeren. Ohne den zweiten
Durchgang findet man gar nichts.

Gelesen wird nur der Eintrag dieses Bildschirms, nachgeschlagen über die
Display-Kennung. In der Datei stehen auch alte Bildschirme, der
Bildschirmschoner und alles, was einmal gesetzt war — das Neueste von allem zu
nehmen führt zuverlässig zu einem Bild, das mit dem Schreibtisch nichts zu tun
hat. Ausprobiert: dabei kam ein weißes Platzhalterbild aus einem Kurzbefehl
heraus. Fehlt der Eintrag oder die Datei, ist ein Systembild die ehrlichere
Antwort als ein Rateergebnis.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 00:08:44 +02:00
ScarriffleandClaude Opus 5 152d36c904 Vorschau: Notch zurück, und der eigene Hintergrund wird wirklich versucht
Die Notch verschwand, sobald zum ersten Mal ein Bild geladen wurde: ein
skalierbares Bild meldet seine eigene Größe als Wunschgröße, und die tausend
Bildpunkte der Vorlage haben den Stapel auf tausend Punkte aufgeblasen. Notch,
Menüleiste und Auslösefläche saßen dann am Rand dieser unsichtbaren Fläche und
lagen außerhalb des Ausschnitts. Vorher fiel es nicht auf, weil nie ein Bild
ankam. Das Bild wird jetzt auf Maß gebracht, bevor es in den Stapel geht.

Und der eigentliche Wunsch: dein Hintergrundbild statt eines Ersatzes. Es
liegt auf dem Schreibtisch, und dorthin fragt macOS beim ersten Lesen einmal
nach. Die Prüfung mit isReadableFile, die ich vorher davorgesetzt hatte,
beantwortet macOS in diesen Ordnern mit „nein", ohne zu fragen — die Vorschau
blieb damit dauerhaft beim Ersatzbild, obwohl eine Freigabe möglich gewesen
wäre. Jetzt wird gelesen statt geprüft, mit den drei nötigen Erklärungen in
der Info.plist. Wird die Freigabe verweigert, bleibt es beim Systembild.

Ein Tahoe-Hintergrund als Ersatz ist nicht drin: unter den Systembildern liegt
davon nur „Tahoe Day.mov", ein Video von 170 Megabyte. Deshalb weiter Sonoma.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:54:11 +02:00
ScarriffleandClaude Opus 5 a2be84f4d5 Absturz beim Laden des Hintergrundbilds — und derselbe Fehler in der Ablage
Was in einer View steht, ist an den Hauptthread gebunden: die Konformität zu
`View` vererbt das, auch an statische Methoden, die damit nichts zu tun haben.
Das Laden lief absichtlich nebenher — und lief damit in die Isolationsprüfung,
die das Programm anhält. Der Compiler hat genau das gemeldet:

  warning: call to main actor-isolated static method 'systemWallpaper()' in a
  synchronous nonisolated context
  note: main actor isolation inferred from conformance to protocol 'View'

Eine Warnung, keine Fehlermeldung. Ich hatte den Bau nur nach `error:`
durchsucht und sie deshalb nicht gesehen.

Das Laden liegt jetzt in einem eigenen Typ neben der View, wo es die Bindung
nicht gibt. Dieselbe Suche über den ganzen Bau hat einen zweiten Fall
gefunden: `FileDropView.stage` wird aus dem Abschlussblock von
`loadFileRepresentation` gerufen, also von irgendeinem Thread, gehört aber zu
einem `ViewModifier`. Das hätte jeden Dateiabwurf auf die Ablage angehalten.

Dazu die Verbesserung, die beim letzten Mal wegen eines falschen
Arbeitsverzeichnisses nicht angekommen ist: gesucht wird zuerst unter den
Originalen und erst danach in `.thumbnails`. Die kleinen Bilder messen 214
Punkte in der Breite und sind auf einem Retina-Schirm sichtbar unscharf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:43:22 +02:00
ScarriffleandClaude Opus 5 6c92e7fed6 Auslösefläche: die Vorschau zeigt wieder einen Bildschirm
Dein Hintergrundbild liegt in ~/Desktop, und dorthin lässt macOS keine App
ohne Freigabe. NSWorkspace gibt den Pfad trotzdem heraus, NSImage gibt danach
still nil zurück — und die Vorschau blieb schwarz, ohne jeden Hinweis worauf.
Gemessen: isReadableFile meldet false, das Laden schlägt fehl.

Um eine Ordnerfreigabe zu bitten, nur um ein Vorschaubildchen zu malen, wäre
die falsche Frage. Also wird jetzt vorher geprüft, ob sich die Datei lesen
lässt, und wenn nicht, kommt ein Standardhintergrund von macOS —
/System/Library/Desktop Pictures, von neu nach alt durchgesehen, hier landet
es bei Sonoma. Die Bilder liegen auf jedem Mac und werden nur gelesen.

Geladen über CGImageSource statt NSImage: die Vorlagen sind 6016 Punkte im
Quadrat und zwanzig Megabyte schwer, gebraucht werden tausend Punkte. Und ein
Hintergrundbild kann mehrere Bilder enthalten, hell und dunkel im selben HEIC.

Das Dekodieren dauert gut hundert Millisekunden, deshalb läuft es neben dem
Zeichnen statt davor — sonst hätte das Fenster beim Öffnen so lange gestanden.
Danach liegt das Bild im Cache.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:30:43 +02:00
ScarriffleandClaude Opus 5 2aa60eedf9 Farben einstellbar — und erst mal überhaupt eine Farbe
Das Grün, das überall auftauchte, war die System-Akzentfarbe: `.tint` und
`.accentColor` werden ohne eigene Angabe dorthin durchgereicht, und das
betraf alle Popovers und das ganze Einstellungsfenster. Die Notch-Widgets
dagegen benutzten Onyx' eigenes Blau. Zwei Farben, ungewollt.

Jetzt eine, und die ist einstellbar. Ein neuer Reiter „Farben": Akzentfarbe
mit sechs Vorschlägen und einem Knopf, der die Systemfarbe übernimmt, dazu
das Paar für Herunter- und Hochladen samt Tauschknopf.

Die Signalfarben bleiben fest und stehen nur zur Ansicht dort. Gelb heißt
Warnung, Rot heißt kritisch, Grün heißt in Ordnung — bei Temperatur, Akku,
Lüfter und Fehlern. Wer sie umstellen kann, kann ihre Bedeutung zerstören;
ein rotes „alles gut" liest niemand richtig. Sichtbar sind sie trotzdem,
sonst sucht man die Warnfarbe im Reiter und findet sie nirgends.

Umgesetzt über die Tokens statt über vierzig Fundstellen: `Onyx.Color.accent`
ist keine Konstante mehr, sondern liest bei jedem Zugriff aus `OnyxTheme`.
Damit merkt SwiftUI die Abhängigkeit und zeichnet neu, sobald die Farbe sich
ändert. Dazu ein `.tint` an den vier Wurzeln — Panel, Popovers, Einstellungen,
Einrichtung —, damit auch Haken, Regler und Auswahlfelder mitziehen.

Nebenbei die Beschriftung: „Je Programm" heißt jetzt „Programme". Großgesetzt
las sich das als englisches „J-E".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:24:40 +02:00
ScarriffleandClaude Opus 5 7a3d2c1c39 Pegel auch für Ausgabe und Mikrofon
Die Programmzeilen hatten ihren mitlaufenden Ausschlag, die beiden Systemregler
nicht. Jetzt beide, in derselben Form: der Pegel läuft im Regler mit, nicht
daneben.

Der Ausgangspegel kommt über einen globalen Tap — denselben Weg wie der Mixer,
nur ohne Stummschalten und ohne Ausgabe. Ausgenommen werden die Programme, die
der Mixer bereits abgreift: ein Tap sieht das Signal vor dem Stummschalten,
sie zählten sonst doppelt — einmal als Original, das niemand hört, und einmal
als das, was Onyx daraus macht. Ändert sich diese Liste, wird der Tap neu
aufgebaut.

Der Mikrofonpegel geht nur mit echter Aufnahme. Es gibt keine Eigenschaft am
Gerät, die den Ausschlag verrät — einen Pegel bekommt nur, wer das Signal
liest, und genau das meldet macOS mit dem orangen Punkt. Das ist richtig so,
also läuft die Messung nur, solange die Ansicht offen ist, und hört beim
Schließen sofort auf. Ein Zähler statt eines Schalters, weil Panel und Popover
gleichzeitig offen sein können.

Geräte, die keine Fließkommawerte liefern, bleiben ohne Pegel: als Fließkomma
gelesene Ganzzahlen ergeben keinen falschen Ausschlag, sondern Unsinn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:17:40 +02:00
ScarriffleandClaude Opus 5 9df2ddb80b Akku-Popover: „Lädt" sitzt auf der Höhe des Rings
Ein HStack zentriert über die volle Höhe seiner Inhalte. Die Beschriftung unter
dem Ring gehört dazu, also rutschte alles daneben um deren halbe Höhe nach
unten. Bei drei Zeilen fällt das kaum auf, bei einer einzelnen schon: „Lädt"
stand sichtbar tiefer als die Mitte, auf die man schaut.

Eine eigene Ausrichtung löst das an der Stelle, an der es entsteht: der Ring
meldet seine Mitte, die Spalte daneben richtet sich danach — unabhängig davon,
wie viele Zeilen sie hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:08:25 +02:00
ScarriffleandClaude Opus 5 e732394c6c Akku-Popover: der Ladezustand steht neben dem Ring, nicht darunter
„Am Netzteil" stand rechts vom Ring, „Am Netz, lädt nicht" darunter — zweimal
dieselbe Auskunft an zwei Stellen. Und die zweite stand allein unter dem
Diagramm, wo sie aussah, als gehörte sie zu dessen Beschriftung.

Jetzt steht beides neben dem Ring: die Schätzung und darunter der Grund dafür.
Am Netz entfällt die Ersatzzeile „Am Netzteil" ganz — die Zeile darunter sagt
ohnehin, was los ist. Im Akkubetrieb ohne Schätzung bleibt „wird berechnet".

Dazu: der Rücksetzknopf im Mixer schaltet den Overdrive mit ab. Er ist keine
eigene Einstellung, sondern die Freigabe für einen Wert, den es danach nicht
mehr gibt — bliebe er stehen, zeigte die Zeile 100 % und der Regler stünde
trotzdem im Boost-Bereich. Der Knopf erscheint deshalb auch, wenn nur der
Overdrive an ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:05:20 +02:00
ScarriffleandClaude Opus 5 ed8b095377 Overdrive je Programm: bis 400 %, aber nur auf Ansage
Der Regler ging bisher immer bis 200 %, ohne dass man das wollen musste. Jetzt
endet er bei 100 % — der Stellung, in der ein Programm klingt, wie es gemeint
war —, und ein Blitz in der Zeile gibt den Bereich darüber frei. Je Programm:
ein Browser braucht ihn für eine leise Konferenz, die Musik daneben nicht.

Oberhalb von 100 % gilt die Kennlinie nicht mehr. Dort steht die Zahl für den
Faktor selbst: 400 % sind das Vierfache der Amplitude. Mit der Kennlinie wären
daraus 4^1,66 ≈ 10,4 geworden — eine Beschriftung, die etwas anderes verspricht,
als der Regler tut. Bei genau 100 % stimmen beide Hälften überein, die Kurve hat
also keinen Sprung, nur einen Knick. Unterhalb bleibt alles wie es war.

Beim Abschalten wird die Lautstärke zurückgeholt. Sonst bliebe ein Programm
dreifach verstärkt, während sein Regler am rechten Anschlag steht und 100 %
anzeigt. Dasselbe beim Laden alter Einstellungen: ein gespeichertes 180 % aus
der Zeit ohne Freigabe fällt auf 100 %.

Die 100 %-Markierung im Regler erscheint nur noch mit Overdrive — ohne ihn läge
sie am rechten Anschlag und sagte dort nichts mehr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:02:43 +02:00
ScarriffleandClaude Opus 5 d001e439a6 Mixer war still: er hat sich selbst abgegriffen
Der Mixer gibt den Ton der bearbeiteten Programme selbst aus — und steht damit
als Tonquelle in seiner eigenen Liste. Eine Zeile wird geregelt, sobald man ihren
Regler anfasst. Ein Klick auf Onyx' eigene Zeile genügte also.

Der Selbst-Tap läuft wie jeder andere mit mutedWhenTapped und schaltet damit
Onyx' gesamte Ausgabe stumm — die Wiedergabe *aller* bearbeiteten Programme.
Völlige Stille, während die Pegelanzeigen weiter ausschlagen, weil die Taps ja
Signal bekommen. Und der Zustand stand in den Einstellungen, überlebte also
jeden Neustart.

Gemessen (Spikes/mixer-path-probe.swift): Onyx' Ausgabepegel klettert von 0,388
auf 2,833, sobald er sich selbst bearbeitet. Der Weg an sich ist in Ordnung —
Tap, Aggregate-Gerät und IOProc liefern einzeln wie zu dritt volle Pegel, das
war der Hauptverdacht und ist widerlegt.

Onyx erscheint jetzt nicht mehr in der eigenen Liste, lässt sich nicht auswählen,
und ein gespeicherter Eintrag wird beim Laden entfernt und zurückgeschrieben.

Dazu ein zweiter Fund aus derselben Ecke: setVolume und setMuted griffen auf
taps[bundleID] zu. Die Taps liegen aber unter Kennung#Prozessnummer, weil ein
Programm mehrere Tonquellen haben kann — der Zugriff ging immer ins Leere. Der
Regler wirkte erst, wenn die Auffrischung drei Sekunden später nachzog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 17:57:15 +02:00
ScarriffleandClaude Opus 5 ed5bd01482 Wetterkachel füllt die Kachel und ist lesbar
Alles stand im oberen Drittel, die untere Hälfte war leer — und die
Stundenwerte in acht Punkten, die man auf Armlänge nicht entziffert.

Der Aufbau folgt jetzt der Reihenfolge, in der man liest: erst was jetzt ist
— großes Symbol, große Temperatur, Höchst- und Tiefstwert daneben, darunter
der Ort und die gefühlte Temperatur —, dann getrennt durch eine Linie, was
noch kommt.

Vier Stunden statt fünf: bei 180 Punkten Breite bleiben so gut vierzig je
Spalte, und die Zahlen lassen sich in einer Größe setzen, die man auch liest.
Die fünfte Stunde war der Grund, warum alles zusammengedrückt war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:07:26 +02:00
ScarriffleandClaude Opus 5 504c518cfb Akku-Popover sagt, was gerade geschieht
„Am Netz" beantwortet die Frage nicht, die man hat, wenn der Ladestand
stehen bleibt: lädt es gerade nicht, weil das Limit erreicht ist, oder
stimmt etwas nicht? Jetzt steht es dort — lädt, angehalten wegen Ladelimit
mit der Prozentzahl, am Netz ohne zu laden, oder Akkubetrieb.

Der Vergleich mit dem Limit hat zwei Punkte Toleranz: der Ladestand pendelt
um die Grenze, und auf das Prozent genau zu vergleichen hieße, den Grund die
halbe Zeit zu verschweigen. Weit unter dem Limit wird dagegen kein
Limit-Halt behauptet — dann steht das Laden aus einem anderen Grund, und
einen falschen zu nennen wäre schlimmer als keinen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:31:19 +02:00
ScarriffleandClaude Opus 5 312514e6ce Eigene Aggregate-Geräte gehören nicht in die Geräteauswahl
Für jedes geregelte Programm legt Onyx ein Aggregate-Gerät an. Sie sind als
privat markiert — das verbirgt sie aber nur vor **fremden** Prozessen, nicht
vor Onyx selbst. In der Ausgabeauswahl standen sie deshalb mitten zwischen
den echten Geräten, und wer eines davon wählt, hängt seinen Ton in eine
Schleife: die Ausgabe eines Taps wird zur Quelle desselben Taps.

Erkannt werden sie über einen Vorsatz in der Gerätekennung, nicht über den
Namen. Der Name enthält den Programmnamen und ließe sich von einem echten
Gerät nicht sicher unterscheiden — die Kennung vergibt Onyx selbst.

Der Vorsatz nennt Onyx beim Namen: taucht so ein Gerät doch einmal irgendwo
auf, im Audio-MIDI-Setup etwa, sieht man, wer es angelegt hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:24:12 +02:00
ScarriffleandClaude Opus 5 c990ea558b Blitz blendet zwischen zwei fertigen Fassungen über
Deine Idee war die bessere. Eine helle Fläche mit dunklem Rand ließ sich aus
einem einzelnen Symbol nur nachbauen, indem dasselbe Zeichen zweimal in
verschiedener Größe übereinander gezeichnet wurde — und die
Größenverhältnisse sahen nie stimmig aus, wie man an den drei Anläufen
sieht. Zwei fertige Fassungen ineinander zu blenden ist der geradere Weg:
gezeichnet wird genau das, was in der Datei steht.

Erst die dunkle voll deckend, dann die helle mit steigender Deckkraft
darüber. Zeichnete man beide anteilig, schiene dazwischen der Hintergrund
durch und der Blitz wirkte blass.

Ohne eigenen Rand bekommt der Blitz den vollen Innenraum des Akkus statt
Innenraum minus Rand — er ist damit wieder etwas größer, bleibt aber
innerhalb des Rahmens. Der Test hält die neue Grenze fest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:20:06 +02:00
ScarriffleandClaude Opus 5 80b083259e Blitz misst sich am Innenraum, nicht an der Außenhöhe
Bezugsgröße war die volle Höhe des Akkus. Der Rahmen nimmt aber oben und
unten je einen Punkt, die Füllung sitzt zwei Punkte eingerückt, und um das
Zeichen kommt noch sein eigener Rand — so füllte der Blitz mitsamt Rand elf
von zwölf Punkten und stieß an den Rahmen.

Jetzt ist der Innenraum die Bezugsgröße: sechs Punkte Zeichen plus zwei Rand
in acht Punkten Innenraum. Ein Test hält fest, dass jedes Zeichen samt Rand
hineinpasst — und dass es nicht ins andere Extrem fällt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:13:41 +02:00
ScarriffleandClaude Opus 5 2bf76eb060 Fehlendes return nachgetragen
Der vorige Commit war nicht übersetzbar: mit einer Zeile vor dem `switch`
ist er kein Ausdruck mehr und braucht ein ausdrückliches `return`. Meine
Prüfung lief in dem Moment gegen ein anderes Verzeichnis und hat den Fehler
nicht gemeldet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:10:37 +02:00
ScarriffleandClaude Opus 5 782d2af4fd Blitz kleiner: der Rand braucht auch Platz
Das Zeichen bekam fast die volle Akkuhöhe, und der Rand kommt außen noch
dazu — dadurch stieß es oben und unten an den Rahmen. Die nutzbare Höhe
zieht den Rand jetzt ab.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:09:48 +02:00
ScarriffleandClaude Opus 5 2490a90519 Blitz aus der mitgelieferten Vorlage, weiterhin fadend
`bolt.fill` aus SF Symbols ist eine massive Fläche; die neue Datei ist eine
Kontur mit kräftigem Strich und trifft die Form besser.

Gezeichnet wird sie zweifach wie zuvor: einmal etwas größer in der
Gegenfarbe als Rand, einmal in der fadenden Farbe darüber. Damit bleibt der
Blitz in jedem Moment des Fadens lesbar — über der hellen Füllung trägt ihn
der Rand, über dem leeren Teil er sich selbst.

Fehlt die Datei, bleibt das Systemsymbol. Dieselbe Vorlage auch in der
Akku-Kachel, damit nicht zwei verschiedene Blitze in einer App stehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:05:34 +02:00
ScarriffleandClaude Opus 5 49e1a46928 Widget-Optionen statt „Quellen", Reiterleiste von der Trennlinie herunter
Die Leiste saß mittig auf der Trennlinie unter dem Titelbalken.
`titlebarAppearsTransparent` allein reichte nicht — macOS zieht darunter
zusätzlich einen Trenner quer durchs Fenster. Der ist jetzt aus. Man setzt
keinen Titel auf eine Trennlinie.

„Quellen" war die Sicht des Programmierers: für den Nutzer ist die
Datenquelle eine Einstellung **des Kalenderwidgets** unter mehreren. Der
Bereich heißt jetzt „Widget-Optionen" und hat einen Abschnitt je Widget.

Kalender: woher die Daten kommen, Monatsraster oder Terminliste — und
endlich, welche Kalender überhaupt mitzählen. Gespeichert werden die
**abgewählten**, nicht die gewählten: kommt ein neuer Kalender dazu, ist er
damit automatisch dabei, statt dass man ihn suchen müsste, ohne zu wissen,
dass es ihn gibt. Der Filter lässt die Abdeckung unberührt — welche Kalender
man sehen will, sagt nichts darüber aus, für welchen Zeitraum Daten
vorliegen.

Wetter: dem Standort folgen oder einen festen Ort setzen, per Stadt oder
Postleitzahl. WeatherKit will Koordinaten, der Nutzer kennt Ortsnamen — die
Umsetzung passiert einmal beim Einstellen statt bei jedem Abruf. Der Ort
überlebt jetzt auch den Neustart; vorher stand nach jedem Start wieder der
Aufenthaltsort da.

Die Ablage-Einstellungen sind vom Widget-Reiter hierher gewandert, wo die
anderen Widget-Optionen stehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:00:48 +02:00
ScarriffleandClaude Opus 5 784b210bc2 Vorschau mit Schreibtischhintergrund, Fenster breit genug für die Reiter
Die Vorschau der Auslösefläche war eine schwarze Fläche — als Bildschirm
kaum zu erkennen. Jetzt liegt der echte Schreibtischhintergrund darunter.
Apples eigene Bilder lassen sich nicht mitliefern (Lizenz, und ein
Tahoe-Hintergrund wiegt zweistellige Megabyte); der eigene ist ohnehin der
bessere Anker, weil man genau ihn wiedererkennt. Fehlt er, bleibt ein
Verlauf in Onyx-Farben.

Dabei fiel auf, dass Notch und Auslösefläche oberhalb des Bildschirms
schwebten statt in ihm zu sitzen: die Rundung lag auf dem Hintergrund
allein, nicht auf dem Ganzen. Sie schneidet jetzt Hintergrund, Menüleiste
und Fläche gemeinsam ab.

Und das Einstellungsfenster war zu schmal für sechs Reiter — die Leiste
wurde rechts abgeschnitten, „Berechtigungen" war nicht mehr erreichbar. 780
statt 620 Punkte, Mindestbreite 740. Beim Nachrechnen der reinen Textbreiten
kommt man auf 560 und liegt damit deutlich daneben: macOS legt je Reiter
Innenabstand und Trenner dazu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:51:37 +02:00
ScarriffleandClaude Opus 5 090f570aba Programmname als Hinweis am Symbol
Seit die Namen aus den Zeilen verschwunden sind, trägt das Symbol die
Erkennung allein — und manche Programme erkennt man daran eben nicht.

Der Hinweis hängt am Symbol und nicht an der Zeile: die Zeile besteht zum
größten Teil aus Regler und Knöpfen, und die verschlucken ihn. Am Symbol
kommt er an, und dort sucht man ihn auch.

Bei mehreren Tonquellen steht ihre Anzahl dabei. Chrome erscheint als eine
Zeile, gibt seinen Ton aber über mehrere Hilfsprozesse aus — die Zahl
erklärt, warum ein Regler mehr als einen Prozess bewegt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:48:51 +02:00
ScarriffleandClaude Opus 5 cfbbf91068 Mixer kann beim Start von Onyx mitlaufen
Ein Häkchen im Mixer selbst. Standardmäßig aus: der Mixer greift in den
Tonweg der geregelten Programme ein, und das soll niemandem ungefragt
passieren — beim ersten Start soll nichts umgeleitet werden, was der Nutzer
nicht angeschaltet hat.

Das Häkchen steht in beiden Zuständen: eingeschaltet, um es wieder
abzuwählen, ausgeschaltet, um es gleich mit zu setzen. Sonst müsste man den
Mixer erst einschalten, um sagen zu können, dass er von selbst einschalten
soll.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:47:17 +02:00
ScarriffleandClaude Opus 5 d7125e28f6 Ablage und AirDrop teilen sich eine Kachel
Zwei eigene Kacheln waren zu viel des Guten: beide zeigen im Ruhezustand
nichts als eine leere Fläche mit einem Satz darin, und zusammen nahmen sie
ein Drittel des Panels.

Jetzt übereinander in einer Kachel — oben die Ablegefläche fürs Senden,
darunter die Ablage mit ihrer Liste. AirDrop steht dabei nebeneinander statt
übereinander: in 52 Punkten Höhe ist für Symbol über Text kein Platz.

Das eigenständige AirDrop-Widget entfällt. Gespeicherte Layouts, die es noch
nennen, verlieren den Eintrag beim Laden — dafür ist der Filter da.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:42:39 +02:00
ScarriffleandClaude Opus 5 57093cb63b Menüleiste: Prozentzeichen ohne Leerzeichen
Die Breite ist fest für „100 %" reserviert, damit nichts springt, wenn der
Wert eine Stelle mehr bekommt. Das Leerzeichen kostet in dieser Reservierung
drei Punkte je Element — in der Menüleiste ist Platz das knappste Gut.

Nur dort. Im Panel und in den Popovern bleibt das Leerzeichen stehen; da ist
Platz, und typografisch gehört es hin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:40:06 +02:00
ScarriffleandClaude Opus 5 4c96aced5a Diagramme rechnen mit der vollen Länge, eigene Symbole für CPU und GPU
Frisch gestartet hat der Verlauf fünf Messwerte statt sechzig. Gerechnet
wurde aber „Breite geteilt durch Anzahl" — also war jeder Balken ein
Fünftel breit, und mit jedem weiteren wurden sie schmaler. Das Diagramm sah
nach einem Ausschlag aus und bedeutete nichts.

Jetzt kommt die Schrittweite aus der vollen Länge. Fehlende Werte bleiben
als freie Fläche links stehen; der Verlauf wächst nach links weg, wie bei
jedem Zeitdiagramm.

Das steckte an **drei** Stellen, alle mit derselben Rechnung: dem
Balkendiagramm im Netzwerk-Popover, der Sparkline in den Kacheln und der
Linie in den Menüleisten-Modulen. Die gemeinsame Rechnung liegt jetzt in
`GraphLayout` und ist geprüft, statt dreimal danebenzugehen.

Nebenbei: die Fläche unter der Sparkline begann am linken Rand statt am
ersten Messwert — ein Keil über die ganze Breite, wo noch nichts gemessen
war.

CPU und GPU bekommen eigene Symbole aus chip.svg und graphic-card.svg. SF
Symbols hat für beides nur denselben Chip, und „cpu" neben „cpu.fill" ist
kein Unterschied, den man in der Menüleiste erkennt.

Die Beschriftung unter den Ringen klebte am Rand und sah aus, als gehörte
sie noch hinein — sechs Punkte Abstand statt zwei. Und die Popover für CPU
und GPU tragen jetzt einen Titel: bei drei gleich aussehenden Ringen sieht
man sonst nicht, vor welchem man steht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:33:28 +02:00
ScarriffleandClaude Opus 5 43ce40676b Eigenes Symbol für den Mixer in der Menüleiste
Die Datei lag im Projektstamm; von dort wird nichts mitgeliefert. Jetzt in
Onyx/ und damit im Bundle.

Gezeichnet wird sie in `labelColor`, nicht in Weiß: unter einer hellen
Menüleiste wäre ein weißes Symbol unsichtbar. Auf dunklem Grund ist
labelColor weiß, also genau das Gewünschte — und auf hellem Grund schwarz,
statt zu verschwinden.

Eigene Vorlagen lassen sich nicht wie SF-Symbole einfärben: dort greift die
Symbolkonfiguration nicht, und `color.set()` allein färbt ein Template-Bild
ohnehin nicht. Der Weg ist, das Bild zu zeichnen und die Farbe mit
`sourceAtop` darüberzulegen — das trifft die deckenden Bildpunkte und lässt
den Rest frei.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:23:21 +02:00
ScarriffleandClaude Opus 5 c0c5809c96 Rücksetzknopf im Mixer, mit reserviertem Platz
Ein kleiner Pfeil je Programm stellt die Lautstärke auf 100 % zurück. Er
erscheint nur, wenn der Wert davon abweicht — es gibt sonst nichts
zurückzusetzen.

Der Platz dafür ist trotzdem **immer** reserviert. Ein Knopf, der auftaucht
und dabei den Regler schmaler macht, verschiebt genau das, was man gerade
bedient: man zieht auf 90 %, der Knopf erscheint, der Regler schrumpft, und
der Griff sitzt woanders als die Hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:18:27 +02:00
ScarriffleandClaude Opus 5 c44bb3af30 Menüleiste springt nicht mehr, Mixer fasst Hilfsprozesse zusammen
Die Breite folgte der Stellenzahl des aktuellen Werts. Aus „14 KB/s" wird
„431 KB/s", und mit der zusätzlichen Stelle wanderte die halbe Leiste. Jetzt
wieder feste Breiten, bemessen am breitesten Wert, der vorkommen kann.

Der frühere Fehler war nicht die feste Breite, sondern der falsche
Bezugswert: gezeichnet wird „63°", bemessen wurde „100 °C" — fünfzehn Punkte
für zwei Zeichen, die nie erscheinen. Nachgemessen: zwei Aufnahmen im
Abstand von sechs Sekunden mit geänderten Werten ergeben identische Breiten.

Der Mixer fasst Hilfsprozesse mit ihrem Programm zusammen. „Google Chrome"
und „Google Chrome Helper" standen als zwei Zeilen nebeneinander, mit
getrennten Reglern für dasselbe Programm — zieht man den einen, hört man
den anderen. Chrome hat je Tab einen Helfer; fünfzehn Regler für einen
Browser sind keine Auskunft.

Abgegriffen wird weiterhin je Prozess, geregelt aber je Programm. Der
Schlüssel der Taps muss deshalb den Prozess mitführen: mehrere Helfer teilen
sich eine Kennung und überschrieben sich sonst gegenseitig. Der Pegel einer
Zeile ist der lauteste ihrer Prozesse.

Die Zeilen sind einzeilig statt zweizeilig: Symbol, Stummschalter, Regler,
Wert. Der Name ist weg — bei einem erkennbaren Programmsymbol ist er
redundant, und die gewonnene Zeile macht die Liste halb so hoch. Dafür ist
das Symbol größer, und wer den Namen braucht, hält den Zeiger darauf.
Popover 420 statt 330 Punkte breit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:15:53 +02:00
ScarriffleandClaude Opus 5 e79191d033 Pausenzeichen wieder ausgestanzt
„Weiß mit dünnem Rand" war für den Blitz bestellt, nicht für das
Pausenzeichen — ich hatte es auf beide angewendet. Bei fast vollem Akku
liegt das Zeichen auf weißer Füllung: das Weiß verschwindet darin, übrig
bleiben die dunklen Ränder als zwei Striche.

Das Pausenzeichen ist damit wieder ein Loch in der Füllung. Der Blitz
bleibt weiß mit Rand und fadend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:07:32 +02:00
ScarriffleandClaude Opus 5 8545cc421c Blitz weiß mit Rand — und er fadet weiter
Beides, nicht eines von beiden: das Zeichen ist weiß mit dünnem dunklem
Rand, und beim Laden fadet es.

Der Rand ist dabei immer die Gegenfarbe zur Füllung. Damit bleibt das
Zeichen in jedem Moment des Fadens lesbar — über der hellen Füllung trägt
es der Rand, über dem leeren Teil die Füllung selbst.

Das Pausenzeichen ist niedriger als der Blitz. Es ist von Haus aus höher
gebaut und stieß oben und unten an den Rahmen des Akkus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:04:31 +02:00
ScarriffleandClaude Opus 5 20963f53e2 Am Netz ohne Laden: Pausenzeichen statt Stecker
„Laden angehalten" ist die Aussage. Ein Stecker sagt nur „Kabel steckt",
und das sieht man am Kabel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:00:44 +02:00
ScarriffleandClaude Opus 5 5d261ed3d8 Menüleiste: Breite für die Gestalt, nicht für den Höchstwert
Nachgemessen statt geraten. Das Netzwerkelement war 69 Punkte breit, meine
Rechnung ergab 47 — und die anderen Module lagen konstant 16 darüber. Sechs
Punkte hatte allein das Netzwerk zusätzlich.

Zwei Ursachen. Die Hysterese hielt die Breite auf dem Höchstwert der letzten
zwanzig Sekunden; bei einem Wert, der im Sekundentakt schwankt, ist der fast
immer größer als der aktuelle. Und der Text wurde linksbündig gezeichnet, die
Differenz stand also komplett rechts als Lücke.

Jetzt wird die Breite für die **Gestalt** reserviert: alle Ziffern auf 9
gesetzt, das ergibt die breiteste Zeichenfolge derselben Form. Von 14 auf
37 KB/s bewegt sich damit nichts, und breiter wird es nur, wenn eine Stelle
dazukommt. Gezeichnet wird mittig, damit ein Rest sich auf beide Seiten
verteilt statt rechts zu stehen. Ergebnis: 69 → 57 Punkte.

Die verbleibenden rund 16 Punkte je Element legt macOS selbst um jedes
Statuselement; die Lücken zwischen benachbarten Elementen sind gemessen 0.

Neue Menüleistenmodule starten jetzt mit „Symbol + Wert" statt „Wert" —
bestehende Einstellungen bleiben, wie sie sind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 12:57:13 +02:00
ScarriffleandClaude Opus 5 8f0831391e Blitz fadet, Einstellungsfenster mittig und veränderbar
Der Blitz fadet beim Laden zwischen Weiß und Schwarz — so gewünscht, und
ich hätte vorher fragen sollen statt eine eigene Lösung zu bauen und sie
hinterher zu begründen.

Über den Kosinus statt linear: ein linearer Ping-Pong knickt an den
Umkehrpunkten sichtbar. Der Zeitgeber läuft mit 30 Bildern je Sekunde und
nur, solange geladen wird — steht das Kabel nicht drin, läuft gar nichts.
Der Stecker für „am Netz, lädt nicht" bleibt ausgestanzt; dort bewegt sich
ohnehin nichts.

Das Einstellungsfenster lässt sich jetzt vergrößern und startet mit
620 × 620 statt 520 × 420. Der Bereich „Displays" passt mit der Vorschau
der Auslösefläche nicht mehr in die alte Höhe, und ein Fenster, in dem man
scrollt, obwohl der Bildschirm frei ist, ist eine Zumutung. Die feste Größe
in der View musste dafür weichen — sonst wächst das Fenster und der Inhalt
bleibt stehen.

Und es öffnet jetzt wirklich mittig. Mein erster Versuch mit 60 Punkten
Abstand von oben war zu zaghaft: der Titelbalken lag weiter so hoch, dass
man auf dem Weg zu seinen Knöpfen durch die Auslösefläche fuhr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 12:52:21 +02:00