Statische Oberfläche vor Aether und InkNote: kein Backend, kein Build, nginx liefert web/ aus. Jede App bleibt ihre eigene PWA auf ihrer eigenen Domain – HoneyOS ist Startpunkt und Umschalter, kein iframe-Rahmen. - zwei Betriebsarten aus einem Datenstand: Terminal (Kacheln, Tastatur) und Desktop (Symbole, verschiebbare Fenster, Taskleiste) - honeybar.js als Drop-in für die Apps, rendert im Shadow DOM, damit Tailwind und die InkNote-Palette einander nicht in die Quere kommen - Konfiguration vollständig aus der .env: das Skript in /docker-entrypoint.d/ schreibt config.json beim Containerstart - optionaler _ME-Pfad pro App zeigt an, wer angemeldet ist; ohne CORS bleibt die Anzeige leer, ohne dass etwas kaputtgeht Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7.0 KiB
HoneyOS
Ein Retro-Schreibtisch vor den eigenen Apps. Amber-CRT, Boot-Log, zwei Betriebsarten — und dieselbe Leiste zum Einhängen in Aether und InkNote.
Was es ist: eine Oberfläche davor. Jede App bleibt ihre eigene PWA auf ihrer eigenen Domain mit ihrer eigenen Arbeitsumgebung und ihrer eigenen Anmeldung. HoneyOS ist der Startpunkt, der Umschalter und die gemeinsame Leiste — kein Rahmen, der die Apps einsperrt (kein iframe).
Was es nicht ist: eine Anmeldung. HoneyOS ist eine statische Seite ohne Backend; ein OIDC-Client bräuchte ein Client-Geheimnis und eine Sitzung, und beides gehört nicht in etwas, das der Browser vollständig lesen kann. Angemeldet wird bei Aether und InkNote, die beide an PocketID hängen. HoneyOS kann den Stand nur anzeigen — siehe unten.
Betrieb
cp .env.example .env # Adressen und Namen eintragen
docker login gitea.honeyy.duckdns.org
docker compose pull && docker compose up -d
Es gibt nichts zu sichern: keine Datenbank, kein Volume. Der ganze Zustand ist die .env —
und was sich der Browser pro Gerät merkt (Betriebsart, Röhrenfarbe).
Hinter deinem Reverse Proxy erwartet HoneyOS nichts Besonderes: proxy_pass auf den Port,
fertig. /healthz antwortet mit ok.
Konfiguration
Alles kommt aus der .env. Beim Containerstart schreibt
docker-entrypoint.d/20-honeyos-config.sh
daraus config.json, die der Browser liest. Nach jeder Änderung docker compose up -d.
Alles darin ist öffentlich. Adressen und Namen gehören hinein, Geheimnisse niemals.
Eine App entsteht durch ihre _URL; fehlt die, wird die Nummer übersprungen (bis 12):
HONEYOS_APP_1_ID=aether
HONEYOS_APP_1_NAME=AETHER
HONEYOS_APP_1_SUBTITLE=Cloud & Dateien
HONEYOS_APP_1_URL=https://cloud.honeyy.duckdns.org
HONEYOS_APP_1_GLYPH=cloud # cloud | note | box | chip | folder | gear
HONEYOS_APP_1_KEY=1 # Zifferntaste im Terminal-Modus
HONEYOS_APP_1_ME=/api/v1/auth/me # optional, siehe „Wer ist angemeldet"
Ohne HONEYOS_APP_1_URL bleibt die eingebackene web/config.json gültig — ein
docker run ohne .env zeigt also die Standard-Apps. Adressen lassen sich zusätzlich im
Browser unter Einstellungen überschreiben; das gilt dann nur für dieses Gerät.
Zwei Betriebsarten, ein Datenstand
| Terminal-Modus | Desktop-Modus | |
|---|---|---|
| Apps | Kacheln nebeneinander | Symbole auf der Fläche, Doppelklick öffnet |
| Fenster | Dialog in der Mitte | verschiebbar, minimierbar |
| unten | Statuszeile mit Tastenhinweisen | Taskleiste mit Startmenü |
Umschalten mit M, über Einstellungen → Betriebsart oder im Startmenü.
Gleich bleiben in beiden: die Menüleiste oben, die Palette, die Einstellungen, config.json.
renderTiles() und renderDeskIcons() in os.js zeichnen aus denselben Daten — eine neue
App erscheint ohne Zutun in beiden.
Tasten: 1 2 App starten · M Betriebsart · S Einstellungen · ? Hilfe ·
Esc schließt Startmenü, oberstes Fenster oder Dialog — in dieser Reihenfolge.
Die Leiste in Aether / InkNote
Eine Zeile ins frontend/index.html der App:
<script src="https://os.honeyy.duckdns.org/honeybar/honeybar.js"
data-app="aether"></script>
data-app ist die id aus der Konfiguration — danach markiert sich die Leiste selbst als
aktiv. Die App-Liste holt sie von allein neben ihrem eigenen Skript.
Sie rendert in einem Shadow DOM: Tailwind (Aether) und die InkNote-Palette kommen nicht
hinein, ihre Stile nicht hinaus. Sie schiebt den Seiteninhalt um 32 px nach unten
(data-push="none" legt sie stattdessen darüber). Rechnet die App mit voller Höhe:
.app-shell { height: calc(100vh - var(--honeybar-h, 0px)); }
Vorschau ohne Einbau: /honeybar/demo.html.
Wer ist angemeldet
_ME ist der Pfad, unter dem eine App „wer bin ich" beantwortet (relativ zur _URL oder
absolut). Aus der Antwort wird der Anzeigename gefischt — display_name, displayName,
name, username, auch verschachtelt unter user.
Gelesen wird das an zwei Stellen, und die verhalten sich unterschiedlich:
- Die Leiste in der App fragt ihre eigene App. Gleicher Ursprung → funktioniert sofort, ohne Änderung an Aether oder InkNote.
- Der Desktop auf
os.…fragt über die Domaingrenze. Dafür muss die App diesen Ursprung erlauben:- InkNote:
ALLOWED_ORIGINS=https://os.honeyy.duckdns.org - Aether: CORS mit
Access-Control-Allow-Credentials— noch nicht vorhanden
- InkNote:
Fehlt das, bleibt die Anzeige leer und sonst passiert nichts. Die Lampe „online" funktioniert unabhängig davon weiter.
_TOKEN_KEY brauchen nur Apps, die einen Bearer-Token im localStorage halten statt eines
Cookies (InkNote: inknote_token). Der ist pro Domain sichtbar — von os.… aus also nicht
lesbar, für die Leiste in der App dagegen schon.
Voraussetzung für all das: alle Adressen liegen unter derselben Domain
(*.honeyy.duckdns.org). Sonst behandelt der Browser sie als fremde Site und schickt die
Sitzung gar nicht erst mit.
Entwickeln
docker compose -f docker-compose.dev.yml up -d --build # → http://localhost:8088
web/ ist gemountet: Datei ändern, Seite neu laden. Weil der Mount schreibgeschützt ist,
greift dort die .env-Konfiguration nicht — es gilt die eingebackene web/config.json.
Zum Prüfen der .env das echte Image nehmen (docker compose up -d --build).
web/
index.html Desktop
style.css alle Farben in den --p*-Variablen ganz oben
os.js Boot, beide Ansichten, Fenster, Einstellungen
config.json Standardkonfiguration (wird zur Laufzeit aus der .env ersetzt)
honeybar/ die einbettbare Leiste + Vorschauseite
looks/ zwei verworfene Entwürfe (System 7, Win95) — nur Ansicht
Neue Symbole sind 12×12-Pixelraster in os.js (GLYPHS).
Bauen und schieben
./build.sh # → gitea.honeyy.duckdns.org/docker/honeyos:latest
./build.sh 0.2 # mit Tag
Grenzen, die man kennen sollte
- localStorage ist pro Domain. Betriebsart und Röhrenfarbe auf
os.…kennt die Leiste aufnotes.…nicht. Der Umschalter ist ein Schalter, kein geteilter Zustand. - Die Lampe ist kein Health-Check. Bei einer fremden Domain darf der Browser nur sehen, dass geantwortet wurde, nicht was. Ein 500er sähe aus wie „online".
config.jsonundhoneybar.jsgehen mitAccess-Control-Allow-Origin: *raus, weil die anderen Domains sie holen. Öffentliche Konfiguration — nichts Vertrauliches hinein.
Was als Nächstes ansteht
- CORS in Aether für
os.…, damit der Desktop den Anmeldestand sehen kann. InkNote hat mitALLOWED_ORIGINSschon den Haken dafür. - Überall abmelden in der Leiste. Braucht pro App den CSRF-Weg zum Logout — bei Aether
ein
POSTmit Token, das geht nicht nebenbei über die Domaingrenze. - Fenster mit Inhalt statt nur Verweisen: „letzte Dateien", „letzte Notizen". Fenster zeigen dann Daten aus den APIs — die Apps selbst bleiben in ihrem eigenen Tab.