---
title: Vorlesen
description: >-
  Ein „Diese Seite anhören“-Player, der jede Seite vorliest und den gerade gelesenen Satz hervorhebt – mit den Browserstimmen deiner Leser oder mit neuronalen Stimmen, die beim Build erzeugt werden.
---

Die Vorlesefunktion fügt unter der Beschreibung jeder Seite einen Player **Diese Seite anhören** hinzu. Deine Leser drücken auf Play, und die Seite wird vom Titel an vorgelesen. Der gerade gelesene Satz wird dabei hervorgehoben und bleibt immer sichtbar. Die Funktion ist standardmäßig aus und du schaltest sie so ein:

```ts blume.config.ts lineNumbers
export default defineConfig({
  narration: true,
});
```

Mit `true` werden Seiten mit den [Browserstimmen](#browser-voices) deiner Leser vorgelesen. Du brauchst keinen Schlüssel und keinen Build-Schritt, und es funktioniert auf jedem Host, ob statisch oder nicht. Wenn du stattdessen [generierte Stimmen](#generated-voices) nutzen willst, füge einen `provider` hinzu.

## Was vorgelesen wird [#what-it-reads]

Vorgelesen werden der Reihe nach der Seitentitel, die Beschreibung, Überschriften, Absätze, Listeneinträge und Kartentexte. Vor manchen Komponenten kommt ein kurzer gesprochener Hinweis, damit Zuhörende wissen, welche Art von Inhalt als Nächstes folgt:

| Komponente | Hinweis |
| --- | --- |
| [Callouts](/de/docs/content/syntax#callouts) | „Hinweis.“, „Tipp.“, „Warnung.“ usw. |
| [Steps](/de/docs/content/components#steps) | „Schritt 1.“, „Schritt 2.“ |
| [Tabs](/de/docs/content/components#tabs) | „macOS-Tab.“ Jeder Tab wird vorgelesen, nicht nur der geöffnete |
| [Accordions](/de/docs/content/components#accordion) und [Expandable](/de/docs/content/components#expandable) | „Ausklappbarer Abschnitt.“ |

Kommt das Vorlesen bei einem geschlossenen Abschnitt oder einem ausgeblendeten Tab an, wird er geöffnet. So landet die Hervorhebung immer auf Text, den deine Leser auch sehen.

Codeblöcke, Tabellen, Bilder, Videos, Diagramme, mathematische Formeln, Typtabellen, Dateibäume und Live-Vorschauen von Komponenten werden übersprungen, weil sie vorgelesen keinen Sinn ergeben.

Der Player erscheint nur auf Seiten mit so viel Fließtext, dass sich das Zuhören lohnt, also etwa ab 50 Wörtern. Sehr kurze Seiten und Seiten, die vor allem aus Code oder API-Feldern bestehen, bekommen keinen Player.

## Zuhören [#listening]

Während eine Seite abgespielt wird, bleibt der Player unter dem Header fixiert. Er hat Play und Pause, Tasten für den vorherigen und nächsten Satz, einen Fortschrittsregler, die bisher gelesene Zeit neben der Gesamtlänge der Seite und eine Geschwindigkeitsregelung von 0,8× bis 2×. Die Geschwindigkeit wird für die nächste Seite gespeichert.

Die Seite scrollt mit, damit der gerade gelesene Satz sichtbar bleibt. Scrollen deine Leser weg, hört die Seite auf mitzuscrollen, aber der Ton läuft weiter. Wer zum Satz zurückscrollt oder auf **Mitlesen** drückt, schaltet das Mitscrollen wieder ein. Wird eine andere Seite geöffnet, stoppt das Vorlesen.

## Browserstimmen [#browser-voices]

`narration: true` liest die Seite mit der [Web Speech API](https://developer.mozilla.org/docs/Web/API/SpeechSynthesis) und den Stimmen auf dem Gerät deiner Leser vor und wählt eine Stimme für die Sprache der Seite. Hat ein Browser keine Stimme für diese Sprache, bleibt der Player ausgeblendet, statt die Seite mit falschem Akzent vorzulesen.

Dafür musst du nichts tun und es kostet nichts. Wie es klingt, hängt aber vom Gerät ab. Die Systemstimmen unter macOS, iOS und Windows klingen gut, während manche Linux-Browser nur wenige oder gar keine Stimmen mitbringen.

## Generierte Stimmen [#generated-voices]

Übergib einen `provider`, um beim Build Audio mit einem neuronalen Sprachsynthesemodell zu erzeugen. Der Provider ist derselbe [`gateway()`](/de/docs/configuration/assistant#adapters)-Adapter, den auch der Assistent verwendet, nur mit einem Sprachsynthesemodell:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { gateway } from "blume/ai";

export default defineConfig({
  narration: {
    provider: gateway({
      model: "openai/tts-1-hd",
      voice: "alloy",
    }),
  },
});
```

`blume build` liest jede gebaute Seite genau so, wie der Player sie vorlesen wird, und teilt sie in Sätze auf. Dann erzeugt es über das [Vercel AI Gateway](https://vercel.com/docs/ai-gateway) einen Clip pro Satz. Die Clips und ein kleines Manifest pro Seite landen als statische Dateien unter `/blume-narration/` in deinem Build. Erneutes Abspielen kostet also nichts, und auf keinem Server läuft etwas.

Bevor etwas generiert wird, gibt der Build aus, wie viele neue Clips er braucht und wie viele Zeichen sie umfassen. So siehst du die Kosten schon vorher:

```txt
Generating narration: 214 new clip(s), 15,880 characters, with openai/tts-1-hd
```

| Option | Standard | Beschreibung |
| --- | --- | --- |
| `model` | `openai/tts-1-hd` | Ein Sprachsynthesemodell aus dem Gateway: `openai/tts-1`, `openai/tts-1-hd`, `fish-audio/s2.1-pro`, `spacexai/grok-tts` und weitere Modelle, die das Gateway anbietet. |
| `voice` | `alloy` | Die Stimme des Modells. |
| `instructions` |  | Wie die Stimme klingen soll, bei Modellen, die Anweisungen annehmen („Lies ruhig vor, wie eine Lehrkraft“). |
| `apiKeyEnv` | `AI_GATEWAY_API_KEY` | Die Umgebungsvariable mit dem Gateway-Schlüssel. Auf Vercel funktioniert auch das OIDC-Token des Builds. |
| `headers` |  | Statische Header, die mit jeder Anfrage gesendet werden. |
| `providerOptions` |  | Wird unverändert an `generateSpeech` aus dem AI SDK weitergegeben, für Modelleinstellungen, die Blume nicht selbst kennt. |

### Caching

Clips werden in `node_modules/.cache/blume/narration` gecacht. Der Cache-Schlüssel besteht aus allem, was ihren Klang bestimmt: dem Satz, seiner Sprache, dem Modell, der Stimme und den Anweisungen. Bei einem neuen Build zahlst du nur für geänderte Sätze, und ein Satz, der auf vielen Seiten steht, wird nur einmal generiert. Vercel und Netlify stellen `node_modules` aus ihrem Build-Cache wieder her, deshalb wird dort bei einem Deployment nur neu generiert, was sich geändert hat. Bei anderen CI-Systemen cachest du das Verzeichnis zwischen den Läufen selbst.

### Fallbacks

Wo es keine Clips gibt, greifen generierte Stimmen auf Browserstimmen zurück:

- In `blume dev`, weil dort nie Audio generiert wird. Führe `blume build` und `blume preview` aus, um die generierte Stimme lokal zu hören.
- Wenn der Schlüssel beim Build nicht gesetzt ist. Der Build gibt dann eine Warnung aus und überspringt die Generierung.
- Wenn die Generierung fehlschlägt. Der Build bricht beim ersten fehlgeschlagenen Clip ab, weil das AI SDK ihn schon erneut versucht hat, und behält alle bereits gecachten Clips.

## Sprachen [#languages]

Jede Seite wird in ihrer Inhaltssprache vorgelesen. Auf einer [internationalisierten](/de/docs/content/i18n) Site bekommt so jede Locale ihre eigene Stimme. Die gesprochenen Hinweise und die Beschriftungen des Players sind in alle integrierten UI-Sprachen übersetzt. Du kannst sie pro Locale unter `narration` in [`i18n.ui`](/de/docs/content/i18n#translated-ui) überschreiben.

## Für eine Seite ausschalten [#turning-it-off-for-a-page]

Setze `narration: false` im [Frontmatter](/de/docs/content/frontmatter) einer Seite, wenn diese Seite keinen Player bekommen soll:

```yaml
---
title: Changelog
narration: false
---
```

## Inhalte ausschließen [#keeping-content-out]

Mit `data-blume-narration="skip"` schließt du ein Element samt seinem gesamten Inhalt vom Vorlesen aus. Genau so überspringt Blume seine eigenen Typtabellen und Vorschauen, und es funktioniert genauso bei deinen eigenen Komponenten und Islands:

```html
<div data-blume-narration="skip">
  <PricingCalculator />
</div>
```

## Analytics

Wenn jemand mit dem Zuhören beginnt, sendet der Player ein `narration_play`-Event mit der `engine` (`audio` oder `browser`) und dem `path` der Seite. Läuft eine Seite bis zum Ende durch, sendet er `narration_complete`. Beide Events laufen wie die anderen benutzerdefinierten Events über deine [Analytics](/de/docs/configuration/analytics#custom-events)-Adapter.
