# threadnet-call: Fork-Anpassungen für axion1337.chat

Dieses Dokument beschreibt alles, was dieser Fork gegenüber Upstream Element Call ändert. Die
übrigen Dateien in `docs/` sind unverändertes Upstream-Material.

## 1. Warum Fork von `emmick4/element-call` (Branch `livekit`)?

Nicht direkt von `element-hq/element-call` geforkt, sondern von `emmick4/element-call`s
`livekit`-Branch, weil dieser bereits den noch nicht upstream gemergten PR
[element-hq/element-call#3736](https://github.com/element-hq/element-call/pull/3736)
enthält - config-driven `media_quality`. Ohne diesen PR wäre eigener Custom-Code nötig gewesen,
um Video-/Audio-Qualitätslimits pro Deployment konfigurierbar zu machen.

## 2. media_quality-Defaults

Konfiguriert in `vite-embedded.config.ts` (im `generateFile`-Plugin-Aufruf, der
`media_quality` in die zur Build-Zeit gebackene `config.json` des Embedded-Packages schreibt):

- Kamera: **1440p / 60fps / ~8 Mbps** (`video.max_resolution/max_framerate/max_bitrate`)
- Screen-Share: **1440p / 30fps / ~6 Mbps**
- 720p-Zwischen-Simulcast-Layer (`video.simulcast_layers`) - ohne diesen fiel die Übertragung
  bei kleinsten Netzwerkschwankungen direkt von 1440p auf blockiges 360p
- `video_codec: "h264"` (siehe Incident unten für die Begründung)

Das sind Startwerte, keine harten Limits - Nutzer können in den Call-Settings weiter hochdrehen.

## 3. VP9-Incident (2026-07-28) — ⚠️ nicht ohne Browser-Repro erneut versuchen

Erster Versuch setzte `video_codec: "vp9"` (Commit `83db5224`). Das hat Calls **live komplett
kaputt gemacht** (kein Bild/Ton), obwohl die LiveKit-SFU-Server-Logs den
Codec-Regression-Fallback auf VP8 als scheinbar erfolgreich zeigten. Sofort zurückgerollt
(Commit `f845d81e`). Vermutete Ursache: LiveKit nutzt für VP9/AV1 SVC statt klassischem
Simulcast, aber `buildPublishOptions()` in diesem Fork setzt immer Simulcast-Layer - ein
echter Code-Fix wäre nötig, um das aufzulösen. **Root Cause nie abschließend isoliert** (hätte
einen Browser-Konsolen-/WebRTC-Internals-Repro gebraucht). Danach auf 720p-Zwischen-Layer +
`h264` (klassisches Simulcast, kein SVC-Risiko, oft hardwarebeschleunigt v.a. auf iOS)
umgestellt - live verifiziert (7/8 Tracks nativ H.264, 1 sauberer VP8-Fallback).

**Nicht erneut versuchen, ohne vorher einen echten Browser-Repro zu haben.**

## 4. npm-Publish zu Gitea (`@sorb/threadnet-call-embedded`)

Das Embedded-Package (`embedded/web/package.json`, aktuell `0.19.2-threadnet.5`) wird zu
Gitea's npm-Registry veröffentlicht (`https://rohana.axion1337.de/api/packages/sorb/npm/`,
Scope `@sorb`). Der obere Versionierungs-Track hier (`0.19.2-threadnet.N`) ist unabhängig von
den Docker-Image-Tags, unter denen das fertig gebaute Widget im gitops-Repo deployt wird (z.B.
`v0.2.3-elementcall-h264` als `threadnet-web`-Image-Tag) - zwei getrennte Versionsschemata für
zwei verschiedene Artefakte (npm-Package vs. Docker-Image).

Der aktuelle Publish-Vorgang läuft manuell/lokal - das committete
`.github/workflows/publish-embedded-packages.yaml` zielt noch auf `registry.npmjs.org`/
`@element-hq`-Scope (Upstream-Konfiguration, nicht an die Gitea-Registry angepasst). Registry-
Zugangsdaten liegen in einer lokalen, **nicht committeten** `.npmrc` - nicht Teil dieses Repos.

## 5. Bewusst keine Server-seitige ML-Rauschunterdrückung

Nur der client-seitige WebRTC-Standardtoggle (Echo/Noise/Gain-Suppression, aus derselben
Upstream-PR-Linie) wurde übernommen. Bewusst **kein** LiveKit-Agents-basiertes Server-seitiges
ML-Noise-Cancellation (z.B. selbst gehostetes DTLN/RNNoise) - LiveKits eigene Dokumentation
beschreibt diesen Baustein als für AI-Voice-Agents gedacht, nicht für Mensch-zu-Mensch-Calls
(kein unterstützter Weg, bereinigtes Audio an andere Teilnehmer weiterzuleiten).

## 6. Produktname im Widget (`.env.production`)

`VITE_PRODUCT_NAME=aXion1337.Chat` in `.env.production` — eine Zeile, keine
Quelldatei angefasst. Upstream liest den Namen an jeder Stelle als
`import.meta.env.VITE_PRODUCT_NAME || "Element Call"`; die Variable zu setzen ist
deshalb die vollständige Umbenennung **ohne Merge-Reibung**.

Der Name folgt der Regel aus `management/shared/branding.md`: „in der Anwendung"
heißt es aXion1337.Chat — und das Call-Widget läuft in der Anwendung.

**Was dadurch tatsächlich umbenannt wird** (Inventur 2026-08-06, embedded-Modus):

| Stelle | sichtbar wo |
|---|---|
| `error.matrix_rtc_transport_missing` | Fehlermeldung „Der Server ist nicht für … konfiguriert" |
| `error.open_elsewhere_description` | „… wurde in einem anderen Tab geöffnet" |
| `DeveloperSettingsTab` Versionszeile | Einstellungen → Entwicklermodus |
| `usePageTitle` → `document.title` | im iframe unsichtbar, der Vollständigkeit halber |

**Was im Embedded-Build ohnehin nie erscheint** — und deshalb *nicht* angefasst
wurde:

- **Die Logo-SVGs.** Alle vier sind importiert und liegen im Bundle — gerendert wird
  im Widget aber keins, und zwar jeweils durch dieselbe Bedingung gesperrt:

  | SVG | gerendert von | Sperre |
  |---|---|---|
  | `Logo` | `Header.tsx` (`HeaderLogo`) | `FullScreenView` zeigt den Header nur bei `header === "standard"` |
  | `LogoMark`, `LogoType` | `CallFooter.tsx` | `showLogo = headerStyle === HeaderStyle.Standard` |
  | `LogoLarge` | `LoginPage`, `RegisterPage` | gibt es nur standalone |

  `HeaderStyle.Standard` ist der Default für **Nicht**-Widget-Nutzung; als Widget ist
  der Header `None` (Desktop) oder `AppBar` (Web/Mobile) — siehe `UrlParams.ts`. Das
  gilt auch für Fehlerseiten: `FullScreenView` prüft dieselbe Bedingung, ein Absturz
  im Widget zeigt also kein Logo.

  ⚠️ Nicht danach greppen, ob ein Logo „irgendwo vorkommt" — im gebauten Bundle steht
  `<desc>Element Call (Beta)</desc>` aus `Logo.svg` drin, obwohl es nie gezeichnet
  wird. Maßgeblich ist die Render-Bedingung, nicht der Treffer.
- **`header_label` („Element Call-Startseite") und `login_subheading`.** Startseite
  und Login gibt es nur im Standalone-Modus.
- **Die drei deutschen `developer_mode.matrixRTCMode.*.description`.** Die reden über
  *Gegenstellen* („alle beteiligten Element Call Clients v0.17.0 oder neuer") — das
  ist eine Kompatibilitätsaussage über fremde Clients, keine Selbstbezeichnung. Sie
  umzubenennen wäre inhaltlich falsch.

⚠️ `build:embedded:development` läuft mit `--mode development` und lädt
`.env.production` nicht — ein Dev-Build zeigt weiter „Element Call". Beabsichtigt;
ausgeliefert wird der Produktions-Build.

**Verifiziert** am CI-Artefakt von Pipeline 189 (`077dd43`), nicht am Quelltext: das
gebaute Bundle enthält „aXion1337.Chat"; die verbliebenen „Element Call"-Treffer sind
Source-Maps, die 22 Sprachdateien (`header_label`, standalone) und die
`<desc>`-Zeile aus `Logo.svg` — keine davon im Widget sichtbar.

## Repo-Topologie (seit 2026-07-31)

**Kanonisch ist `git.lab/axion1337.chat/threadnet-call`** (Homelab-GitLab) — die Kopie auf
`rohana.axion1337.de/sorb/threadnet-call` ist ein automatischer **Push-Mirror** (Lesekopie,
Issues, npm-Registry). **Niemals direkt nach rohana pushen** — der Mirror überschreibt
divergente Stände.
