Anfuehrungszeichen: 199 falsche Schlusszeichen im sichtbaren Text

Deutsch oeffnet mit „ und schliesst mit “. An 199 Stellen, die ein
Mensch liest, stand als Schlusszeichen ein GERADES " -- „Nächstes"
statt „Nächstes“. Auf sechzehn oeffentlichen Seiten, in vierzig
Dateien des Workspace und in zwoelf Servermodulen, die Texte
verschicken.

Auf dem Bildschirm sieht man den Unterschied sofort. Beim Schreiben
nicht: Das gerade " liegt auf der Tastatur, die anderen nicht.

WARUM EIN ERSTER ANLAUF ZURUECKGENOMMEN WURDE

Ein gerades " ist an vielen Stellen SYNTAX und kein Schriftzeichen --
Grenze einer Zeichenkette, Grenze eines HTML-Attributs, Zeichen in
einem regulaeren Ausdruck. Wer stumpf ersetzt, macht aus

    „<a href="https://…                  ein kaputtes Attribut
    /^["'„»\s]+|["'“«.\s]+$/              einen kaputten Ausdruck
    "… nichts „mal " + "eben …"          eine kaputte Zeichenkette

DIE UNTERSCHEIDUNG LAEUFT AN MERKMALEN, NICHT AN EINER LISTE

  < > = dazwischen        -> HTML-Marke oder Attribut
  endet auf Leerzeichen   -> die Zeichenkette hoert hier auf, der
                             Satz geht in der naechsten Zeile weiter.
                             Ein deutsches Schlusszeichen steht NIE
                             hinter einem Leerzeichen.
  Rueckstrich mittendrin  -> regulaerer Ausdruck
  ${ ohne }               -> mitten in einem Ausdruck

Eine Liste erlaubter Ausnahmen waere die naechste, die niemand
pflegt. Zwoelf Stellen bleiben dadurch stehen, alle zwoelf einzeln
angesehen und alle zwoelf zu Recht -- dort steht das richtige
Schlusszeichen ohnehin weiter unten im Satz.

Fuenf davon waren allerdings ECHTE Fehler HINTER dem Link
(`…>HasiDog</a>".`) -- die erste Regel hatte nur das Attribut
gesehen, nicht den Satz danach. Gezielt nachgezogen.

Ein maskiertes `\"` in workspace-vorlagen.js (28 Hooks) wird zu “ --
ohne Rueckstrich, denn “ begrenzt nichts.

KOMMENTARE BLEIBEN, WIE SIE SIND. Dort liest es niemand ausser mir;
eine Wache, die auch Kosmetik anmahnt, wird weggeklickt. Beim ersten
Messen fielen ausserdem acht Stellen aus buehne.html faelschlich an,
weil `/* */` in HTML (in <style> und <script>) nicht ausgeblendet
war -- jetzt schon.

DIE WACHE DAZU

pruef-struktur prueft es ab sofort mit derselben Regel: 322 Dateien
mit sichtbarem Text, 0 Funde, und die zwoelf bewussten Ausnahmen
werden GEZAEHLT und genannt (erlaubt: 12). Eine Ausnahme, die niemand
sieht, waechst -- und irgendwann steht der echte Fall darin.

GEPRUEFT

  pruef-struktur   59 -> 68 Pruefungen, 0 Fehler
  node --check auf allen geaenderten JS-Dateien
  nachgemessen: 199 geaendert, 12 mit Grund stehen geblieben

  gruen geblieben: bewerbung-aufgaben 163, nachwuchs 262,
  reaktion 421, support 63, content 45, terminregel 35, treff 85

  Und nachgesehen, ob eine Pruefung noch die alte Schreibweise
  ERWARTET: 13 Fundstellen, alle dreizehn nur Text in ihrer eigenen
  Ausgabe, keine einzige ein Vergleich mit dem Seitentext.

GEGENPROBE: In reaktion.html ein Schlusszeichen zurueckgedreht ->
„workspace/reaktion.html:546 „Nächstes"", mit Datei und Zeile. Und
die Erkennung einzeln gegen HTML-Attribut, fortgesetzte
Zeichenkette, regulaeren Ausdruck und eingesetzten Wert geprueft.

Stempel gesetzt: workspace 670 Verweise in 45 Dateien, oeffentlich
554 in 48 Seiten.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-10-01 01:56:15 +02:00
co-authored by Claude Opus 5
parent 7dc5356c80
commit 95c4599baa
138 changed files with 1510 additions and 1390 deletions
+121 -1
View File
@@ -28,7 +28,7 @@
werden. Eine Pruefung, die immer bestaetigt, bestaetigt nichts. */
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
import { join, dirname, resolve } from "node:path";
import { sep, join, dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { brotliCompressSync, constants } from "node:zlib";
@@ -772,6 +772,126 @@ console.log(`\n=== Laedt jedes Server-Modul? ===`);
Deshalb wird es hier gesucht, statt darauf zu warten, dass es wieder
jemanden trifft. Gemeint ist nur das TAGESDATUM; ein Zeitstempel
(`erstellt`) darf und soll UTC sein. */
console.log(`\n=== Das deutsche Schlusszeichen ===`);
/* ===================================================================
AM 01.10.2026 NACHGEMESSEN: 199 Stellen, die ein Mensch liest,
schlossen ein deutsches Anfuehrungszeichen mit einem GERADEN " --
auf sechzehn oeffentlichen Seiten, in vierzig Dateien des
Workspace und in zwoelf Servermodulen, die Texte verschicken.
Deutsch oeffnet mit \u201E und schliesst mit \u201C. Auf dem
Bildschirm sieht man den Unterschied sofort; beim Schreiben nicht,
denn das gerade " liegt auf der Tastatur und die anderen nicht.
Ohne Wache sind es in vier Wochen wieder zwanzig.
WAS BEWUSST STEHEN BLEIBT -- und warum die Regel so und nicht
einfacher ist: Ein gerades " ist an vielen Stellen SYNTAX und kein
Schriftzeichen. Es begrenzt eine Zeichenkette, ein HTML-Attribut
oder steht in einem regulaeren Ausdruck. Ein erster Anlauf, der
stumpf ersetzte, musste zurueckgenommen werden.
Die Unterscheidung laeuft an Merkmalen, nicht an einer Liste von
Ausnahmen:
< > = dazwischen -> HTML-Marke oder Attribut
endet auf Leerzeichen -> die Zeichenkette hoert hier auf, der
Satz geht in der naechsten Zeile weiter. Ein deutsches
Schlusszeichen steht NIE hinter einem Leerzeichen.
Rueckstrich mittendrin -> regulaerer Ausdruck
${ ohne } -> mitten in einem Ausdruck
=================================================================== */
{
const AUF = "\u201E"; /* „ */
const ZU = "\u201C"; /* “ */
/* Zusammengesetzt und nicht ausgeschrieben: Sonst zeigte diese
Datei sich beim naechsten Lauf selbst an. */
const suche = new RegExp(AUF + '([^' + ZU + AUF + '"`\n]{1,140})"', "g");
const warumNicht = (innen) => {
if (/[<>=]/.test(innen)) return "HTML-Marke oder Attribut";
if (innen.endsWith(" ")) return "Satz geht in der naechsten Zeile weiter";
if (innen.replace(/\\+$/, "").includes("\\")) return "regulaerer Ausdruck";
if ((innen.match(/\$\{/g) || []).length !== (innen.match(/\}/g) || []).length) {
return "offener Ausdruck";
}
return null;
};
/* WAS EIN MENSCH LIEST: die oeffentlichen Seiten, der Workspace und
die Servermodule, die Texte verschicken. Pruef- und Messdateien
schreiben nur in meine Konsole -- dort waere es Kosmetik, und
eine Wache, die auch Kosmetik anmahnt, wird weggeklickt. */
const sammeln = (ordner, tiefe = 0) => {
const raus = [];
for (const e of readdirSync(ordner, { withFileTypes: true })) {
if (e.name === "node_modules" || e.name.startsWith(".")) continue;
const voll = join(ordner, e.name);
if (e.isDirectory()) { if (tiefe < 4) raus.push(...sammeln(voll, tiefe + 1)); continue; }
if (/\.(js|mjs|html|css)$/.test(e.name)) raus.push(voll);
}
return raus;
};
const dateien = [
...sammeln(join(SERVER, "..", "workspace")),
...sammeln(join(SERVER, "..", "assets")),
...readdirSync(join(SERVER, "..")).filter((n) => n.endsWith(".html"))
.map((n) => join(SERVER, "..", n)),
...readdirSync(SERVER).filter((n) => n.startsWith("workspace-") && n.endsWith(".js"))
.map((n) => join(SERVER, n)),
];
ok(dateien.length > 100, `${dateien.length} Dateien mit sichtbarem Text angesehen`);
const falsch = [];
const stehenGelassen = [];
for (const pfad of dateien) {
const art = pfad.slice(pfad.lastIndexOf("."));
let text = readFileSync(pfad, "utf8")
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
if (art === ".js" || art === ".mjs") {
text = text.replace(/^\s*\/\/.*$/gm, "");
}
/* Der Pfad AB DER WURZEL des Projekts -- ein abgeschnittener
Pfad ist eine Meldung, der man nicht folgen kann. */
const kurz = pfad.split(sep).join("/").split("/DogiHompage/").pop();
for (const t of text.matchAll(suche)) {
const zeile = text.slice(0, t.index).split("\n").length;
const nein = warumNicht(t[1]);
if (nein) stehenGelassen.push(`${kurz}:${zeile} (${nein})`);
else falsch.push(`${kurz}:${zeile} ${AUF}${t[1].slice(0, 40)}"`);
}
}
ok(falsch.length === 0,
falsch.length
? `schliessen ein deutsches Anfuehrungszeichen mit einem geraden ":\n `
+ falsch.slice(0, 15).join("\n ")
+ (falsch.length > 15 ? `\n ... und ${falsch.length - 15} weitere` : "")
: `kein sichtbarer Text schliesst mit einem geraden " (${dateien.length} Dateien)`);
/* DIE AUSNAHMEN WERDEN GEZAEHLT UND GENANNT. Eine Ausnahme, die
niemand sieht, waechst -- und irgendwann steht der echte Fall
darin und faellt nicht mehr auf. */
ok(stehenGelassen.length <= 12,
`${stehenGelassen.length} Stellen bleiben mit Grund stehen`
+ ` (erlaubt: 12) — ${stehenGelassen.slice(0, 3).join(", ") || "—"}`);
/* ---- GEGENPROBEN ------------------------------------------------ */
const findet = (code) => {
const treffer = [...code.matchAll(new RegExp(suche.source, "g"))];
return treffer.filter((t) => !warumNicht(t[1])).length;
};
ok(findet(`Er sagte ${AUF}hallo".`) === 1,
"Gegenprobe: ein gerades Schlusszeichen faellt auf");
ok(findet(`Er sagte ${AUF}hallo${ZU}.`) === 0, " das richtige NICHT");
ok(findet(`${AUF}<a href="x">y</a>`) === 0,
" ein HTML-Attribut ist kein Schlusszeichen");
ok(findet(`"… nichts ${AUF}mal " + "eben …"`) === 0,
" und die Begrenzung einer Zeichenkette, die weitergeht, auch nicht");
ok(findet('/^["\'' + AUF + '»\\s]+|["]/') === 0,
" ein regulaerer Ausdruck ebenfalls nicht");
ok(findet(AUF + "${a.titel}\"") === 1,
" ein eingesetzter Wert dagegen schon");
}
console.log(`\n=== Ruft ein Modul etwas, das es nie eingefuehrt hat? ===`);
/* ===================================================================
AM 01.10.2026 SELBST GEBAUT UND FAST AUSGELIEFERT.
+4 -4
View File
@@ -178,7 +178,7 @@ export function resuemeeVon(antworten, punkte, felder, vorher = null, einordnung
kopf = unklarP === n
? "Diesmal konntest du zu fast allem nichts sagen. Das ist eine ehrliche "
+ "Antwort – und beim nächsten Mal weißt du vermutlich mehr."
: `Alle ${n} Fragen dieser Runde stehen auf „Läuft". Das ist selten, und `
: `Alle ${n} Fragen dieser Runde stehen auf „Läuft“. Das ist selten, und `
+ "es ist kein Zufall – irgendwas machst du gerade richtig.";
} else if (!haktP.length) {
kopf = `Nichts hakt gerade. ${waechstP.length === 1 ? "Eine Sache wächst" : `${waechstP.length} Sachen wachsen`} `
@@ -276,7 +276,7 @@ export function resuemeeVon(antworten, punkte, felder, vorher = null, einordnung
+ "einem Menschen, wie es steht – das ist alles, und es reicht.";
} else if (haktP.length) {
team = themaFeld && themaN > 1
? `Wahrscheinlich bist du damit nicht allein: „${feldName(themaFeld.schluessel)}" `
? `Wahrscheinlich bist du damit nicht allein: „${feldName(themaFeld.schluessel)}“ `
+ "hakt selten nur bei einem. Es in der Runde anzusprechen löst es oft "
+ "für mehrere auf einmal."
: "Eine Sache, die bei dir hakt, hakt selten nur bei dir. Wer sie ausspricht, "
@@ -305,9 +305,9 @@ export function resuemeeVon(antworten, punkte, felder, vorher = null, einordnung
sagt, welches von beidem es ist -- daran hängt, ob man mit
einer Sache spricht oder mit einem Thema. */
satz: themaN > 1
? satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}" `
? satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}“ `
+ `– da stehen ${themaN} der Haken beieinander. Das ist selten Zufall`)
: satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}"`),
: satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}“`),
/* DIE TITEL NUR, WENN ES MEHRERE SIND (22.09.2026).
Bei genau einem stand er zweimal untereinander: einmal hier
und gleich darunter als "Dein naechster Schritt". Im Bild
+2 -2
View File
@@ -332,7 +332,7 @@ callRouter.post("/workspace/api/calls/:id/protokoll", gleicheHerkunft, (req, res
INSERT INTO aufgaben
(titel, beschreibung, status, prioritaet, creator_id, verantwortlich_id, frist, erstellt, erstellt_von)
VALUES (?,?,'offen','mittel',?,?,?,?,?)`).run(
t.titel, `Aus dem Gespräch „${termin.titel}"`,
t.titel, `Aus dem Gespräch „${termin.titel}“`,
termin.creator_id, termin.teilnehmer_id ?? termin.creator_id,
t.frist, jetzt(), req.person.id).lastInsertRowid);
d.prepare("INSERT INTO protokoll_aufgaben (protokoll_id, aufgabe_id) VALUES (?,?)")
@@ -348,7 +348,7 @@ callRouter.post("/workspace/api/calls/:id/protokoll", gleicheHerkunft, (req, res
INSERT INTO termine
(titel, beschreibung, art, beginn, dauer_min, ort, creator_id, teilnehmer_id, erstellt, erstellt_von, haus)
VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(
termin.titel, `Folgetermin zu „${termin.titel}"`, termin.art, nb, dauer,
termin.titel, `Folgetermin zu „${termin.titel}“`, termin.art, nb, dauer,
termin.ort, termin.creator_id, termin.teilnehmer_id, jetzt(), req.person.id,
/* Ein Folgetermin erbt das Haus SEINES Vorgaengers und nicht
das der Adresse: Wer ihn ansetzt, verlaengert etwas, das
+3 -3
View File
@@ -333,8 +333,8 @@ export function darfSchreiben(person, bereich) {
const hat = stufeVon(person);
if (!stufeReicht(hat, noetig)) {
return noetig === "dabei"
? `Ab „${STUFEN_NAME.dabei}" kannst du hier schreiben – das ist nach ${DABEI_TAGE} Tagen so weit.`
: `Ab „${STUFEN_NAME.stamm}" kannst du hier etwas einstellen – nach ${STAMM_TAGE} Tagen `
? `Ab „${STUFEN_NAME.dabei}“ kannst du hier schreiben – das ist nach ${DABEI_TAGE} Tagen so weit.`
: `Ab „${STUFEN_NAME.stamm}“ kannst du hier etwas einstellen – nach ${STAMM_TAGE} Tagen `
+ `und ${STAMM_BEITRAEGE} eigenen Beiträgen.`;
}
return null;
@@ -1023,7 +1023,7 @@ treffRouter.post("/workspace/api/treff/mitmachen/:id/uebernehmen", gleicheHerkun
VALUES ('talente','empfohlen',?,?,?,'mittel','offen',?,?,?,?)`)
.run(
`${wer?.name ?? "Jemand"} hat sich im Rudel gemeldet`,
`Aus „Mitmachen": ${String(e.titel ?? "")}\n\n${String(e.text ?? "")}`.trim(),
`Aus „Mitmachen“: ${String(e.titel ?? "")}\n\n${String(e.text ?? "")}`.trim(),
/* Der TAG in Ortszeit (01.10.2026), der Zeitstempel in UTC. */
heuteLokal(), e.erstellt_von, nun, req.person.id, "Das Rudel");
protokolliere("treff_talent", { personId: req.person.id, ip: echteIp(req),
+28 -28
View File
@@ -86,65 +86,65 @@ const BEREICH_PUNKTE = {};
export const CONTENT_IDEEN = [
/* ---- Wert (70 %) ---------------------------------------------------- */
{ schluessel: "das-haette-ich-am-anfang-gern-gewusst", titel: "Das hätte ich am Anfang gern gewusst",
hook: "„Ich hab drei Monate gebraucht, um das zu kapieren – du brauchst 30 Sekunden.\"",
hook: "„Ich hab drei Monate gebraucht, um das zu kapieren – du brauchst 30 Sekunden.“",
format: "Talking Head", saeule: "Wert", stufe: "anfaenger",
text: "Ein Fehler, den du selbst gemacht hast, und was du heute anders machst. "
+ "Konkret bleiben: ein Fehler, eine Lösung. Wer drei Dinge sagt, sagt nichts." },
{ schluessel: "mein-setup-fuer-unter-100", titel: "Mein Setup für unter 100 €",
hook: "„Alle sagen, du brauchst teure Technik. Hier ist meins für 87 Euro.\"",
hook: "„Alle sagen, du brauchst teure Technik. Hier ist meins für 87 Euro.“",
format: "Zeigen & Erklären", saeule: "Wert", stufe: "anfaenger",
text: "Was du wirklich benutzt, mit Preisen. Ehrlich sein, wo es hakt – "
+ "das ist der Teil, den niemand sonst zeigt." },
{ schluessel: "drei-einstellungen-die-sofort-was-bringe", titel: "Drei Einstellungen, die sofort was bringen",
hook: "„Wenn dein Stream unscharf aussieht, liegt es an einer davon.\"",
hook: "„Wenn dein Stream unscharf aussieht, liegt es an einer davon.“",
format: "Bildschirmaufnahme", saeule: "Wert", stufe: "fort",
text: "Nicht mehr als drei. Jede in unter 15 Sekunden erklärt, mit Vorher/Nachher." },
{ schluessel: "was-ich-in-einer-woche-gelernt-habe", titel: "Was ich in einer Woche gelernt habe",
hook: "„Sieben Tage, eine Erkenntnis – die hier hat alles verändert.\"",
hook: "„Sieben Tage, eine Erkenntnis – die hier hat alles verändert.“",
format: "Talking Head", saeule: "Wert", stufe: "anfaenger",
text: "Rückblick auf eine echte Woche. Funktioniert nur mit einer konkreten Zahl "
+ "oder einem konkreten Moment." },
{ schluessel: "antwort-auf-die-frage-die-immer-kommt", titel: "Antwort auf die Frage, die immer kommt",
hook: "„Das werde ich jeden Tag gefragt – hier einmal in Ruhe.\"",
hook: "„Das werde ich jeden Tag gefragt – hier einmal in Ruhe.“",
format: "Talking Head", saeule: "Wert", stufe: "fort",
text: "Aus dem Chat sammeln, welche Frage sich wiederholt. Die Antwort einmal "
+ "gut aufnehmen und immer wieder verwenden." },
{ schluessel: "so-bereite-ich-einen-stream-vor", titel: "So bereite ich einen Stream vor",
hook: "„Zwei Stunden vor LIVE mache ich immer dasselbe.\"",
hook: "„Zwei Stunden vor LIVE mache ich immer dasselbe.“",
format: "Vlog", saeule: "Wert", stufe: "fort",
text: "Der Ablauf hinter der Sendung. Zeigt Verlässlichkeit und gibt Anfängern "
+ "eine Vorlage." },
{ schluessel: "fehler-die-ich-bei-anderen-sehe", titel: "Fehler, die ich bei anderen sehe",
hook: "„Bitte mach das nicht – ich sehe es jeden Tag.\"",
hook: "„Bitte mach das nicht – ich sehe es jeden Tag.“",
format: "Talking Head", saeule: "Wert", stufe: "profi",
text: "Niemanden bloßstellen. Das Verhalten beschreiben, nicht die Person." },
/* ---- Community (20 %) ------------------------------------------------ */
{ schluessel: "der-beste-moment-aus-dem-letzten-live", titel: "Der beste Moment aus dem letzten LIVE",
hook: "„Das ist gestern passiert, und ich rede immer noch davon.\"",
hook: "„Das ist gestern passiert, und ich rede immer noch davon.“",
format: "Zusammenschnitt", saeule: "Community", stufe: "anfaenger",
text: "Ein Ausschnitt, keine Zusammenfassung. Wer alles zeigt, zeigt nichts." },
{ schluessel: "ich-beantworte-eure-kommentare", titel: "Ich beantworte eure Kommentare",
hook: "„Ihr habt gefragt – jetzt rede ich.\"",
hook: "„Ihr habt gefragt – jetzt rede ich.“",
format: "Talking Head", saeule: "Community", stufe: "anfaenger",
text: "Drei bis fünf echte Kommentare, sichtbar eingeblendet. Auch die kritischen." },
{ schluessel: "danke-an-die-die-immer-da-sind", titel: "Danke an die, die immer da sind",
hook: "„Ihr seid seit dem ersten Stream dabei. Das hier ist für euch.\"",
hook: "„Ihr seid seit dem ersten Stream dabei. Das hier ist für euch.“",
format: "Talking Head", saeule: "Community", stufe: "fort",
text: "Namen nennen, wenn die Leute einverstanden sind. Sonst allgemein bleiben – "
+ "aber ehrlich." },
{ schluessel: "eine-entscheidung-bei-der-ihr-mitredet", titel: "Eine Entscheidung, bei der ihr mitredet",
hook: "„Ich kann mich nicht entscheiden. Ihr habt 24 Stunden.\"",
hook: "„Ich kann mich nicht entscheiden. Ihr habt 24 Stunden.“",
format: "Umfrage", saeule: "Community", stufe: "fort",
text: "Echte Wahl, keine Scheinfrage. Das Ergebnis danach auch wirklich umsetzen." },
/* ---- Eigenwerbung (10 %) --------------------------------------------- */
{ schluessel: "wann-und-wo-ich-streame", titel: "Wann und wo ich streame",
hook: "„Immer dienstags und donnerstags – und ich fange pünktlich an.\"",
hook: "„Immer dienstags und donnerstags – und ich fange pünktlich an.“",
format: "Kurzclip", saeule: "Eigenwerbung", stufe: "anfaenger",
text: "Fester Sendeplan als eigener Clip. Wiederholbar, sobald sich etwas ändert." },
{ schluessel: "was-diese-woche-ansteht", titel: "Was diese Woche ansteht",
hook: "„Drei Sachen, und eine davon habe ich noch nie gemacht.\"",
hook: "„Drei Sachen, und eine davon habe ich noch nie gemacht.“",
format: "Kurzclip", saeule: "Eigenwerbung", stufe: "anfaenger",
text: "Vorschau auf die Woche. Kurz halten, sonst wird es eine Ankündigung "
+ "statt einer Einladung." },
@@ -168,81 +168,81 @@ export const CONTENT_IDEEN = [
/* ---- Wert (70 %) ---- */
{ schluessel: "vorher-nachher-an-meinem-kanal", titel: "Vorher / Nachher an meinem Kanal",
hook: "„So sah mein Stream vor drei Monaten aus. Und so heute.\"",
hook: "„So sah mein Stream vor drei Monaten aus. Und so heute.“",
format: "Vorher / Nachher", saeule: "Wert", stufe: "anfaenger",
text: "Zwei Ausschnitte nebeneinander, dazwischen die eine Sache, die du geändert hast. "
+ "Das Format funktioniert, weil der Zuschauer den Unterschied SIEHT und nicht glauben muss." },
{ schluessel: "drei-sachen-die-dir-keiner-sagt", titel: "Drei Sachen, die dir keiner sagt",
hook: "„Drei Sachen über Streaming, die dir keiner sagt – die dritte hat mich am meisten gekostet.\"",
hook: "„Drei Sachen über Streaming, die dir keiner sagt – die dritte hat mich am meisten gekostet.“",
format: "Nummerierte Liste", saeule: "Wert", stufe: "fort",
text: "Eine Zahl im Aufhänger verspricht ein Ende – deshalb bleiben Leute dran. "
+ "Die stärkste Nummer kommt zuletzt, und sie wird im Aufhänger angekündigt." },
{ schluessel: "ich-teste-was-alle-empfehlen", titel: "Ich teste, was alle empfehlen",
hook: "„Jeder empfiehlt das. Ich habe es zwei Wochen gemacht – hier ist das Ergebnis.\"",
hook: "„Jeder empfiehlt das. Ich habe es zwei Wochen gemacht – hier ist das Ergebnis.“",
format: "Selbstversuch", saeule: "Wert", stufe: "fort",
text: "Ein verbreiteter Ratschlag, von dir selbst überprüft, mit Zahlen davor und danach. "
+ "Widerspruch zieht Aufmerksamkeit – aber nur, wenn du wirklich getestet hast." },
{ schluessel: "so-lese-ich-meine-zahlen", titel: "So lese ich meine Zahlen",
hook: "„Diese eine Zahl sagt mir mehr als die Zuschauerzahl.\"",
hook: "„Diese eine Zahl sagt mir mehr als die Zuschauerzahl.“",
format: "Bildschirm & Erklären", saeule: "Wert", stufe: "profi",
text: "Zeig deine eigene Auswertung: durchschnittliche Verweildauer, Anteil neuer Zuschauer, "
+ "Wiederkehrer. Erklär, was du daraufhin geändert hast. Wenige machen das – deshalb wirkt es." },
{ schluessel: "die-erste-sekunde-entscheidet", titel: "Die erste Sekunde entscheidet",
hook: "„Sag das in Sekunde eins – oder der Zuschauer ist weg.\"",
hook: "„Sag das in Sekunde eins – oder der Zuschauer ist weg.“",
format: "Zerlegung", saeule: "Wert", stufe: "profi",
text: "Nimm ein eigenes Video auseinander: Was hast du in Sekunde eins gesagt, was würdest du "
+ "heute sagen? Über 70 Prozent entscheiden in den ersten drei Sekunden. Zeig beides." },
{ schluessel: "mein-ablauf-als-vorlage", titel: "Mein Ablauf als Vorlage zum Mitnehmen",
hook: "„Hier ist der Ablauf, nach dem ich jeden Stream fahre. Nimm ihn.\"",
hook: "„Hier ist der Ablauf, nach dem ich jeden Stream fahre. Nimm ihn.“",
format: "Zeigen & Weitergeben", saeule: "Wert", stufe: "meister",
text: "Etwas herzugeben, das bei dir funktioniert, kostet nichts und bringt Vertrauen. "
+ "Meisterschaft zeigt sich daran, dass es auch ohne dich funktioniert." },
{ schluessel: "was-hundert-streams-mir-beigebracht-h", titel: "Was hundert Streams mir beigebracht haben",
hook: "„Hundert Streams. Drei Sachen sind übrig geblieben.\"",
hook: "„Hundert Streams. Drei Sachen sind übrig geblieben.“",
format: "Rückblick", saeule: "Wert", stufe: "meister",
text: "Kein Best-of, sondern das, was du heute anders machst als am Anfang. "
+ "Wer lange dabei ist, hat den einen Vorteil, den niemand abkürzen kann." },
/* ---- Community (20 %) ---- */
{ schluessel: "ein-insider-den-nur-ihr-versteht", titel: "Ein Insider, den nur ihr versteht",
hook: "„Wenn du weißt, was das bedeutet, bist du schon länger dabei.\"",
hook: "„Wenn du weißt, was das bedeutet, bist du schon länger dabei.“",
format: "Kurzclip", saeule: "Community", stufe: "anfaenger",
text: "Ein Spruch, ein Emote, ein Moment aus dem Stream. Wer ihn versteht, fühlt sich zugehörig – "
+ "und wer nicht, will dazugehören. Beides hilft." },
{ schluessel: "eure-clips-mein-kommentar", titel: "Eure Clips, mein Kommentar",
hook: "„Ihr habt das aufgenommen. Ich sag euch, was da wirklich los war.\"",
hook: "„Ihr habt das aufgenommen. Ich sag euch, was da wirklich los war.“",
format: "Reaction", saeule: "Community", stufe: "fort",
text: "Clips, die Zuschauer selbst geschnitten haben, mit deinem Kommentar. "
+ "Das belohnt die, die mitmachen – und wer belohnt wird, macht weiter." },
{ schluessel: "die-regel-die-ihr-euch-gewuenscht-hab", titel: "Die Regel, die ihr euch gewünscht habt",
hook: "„Ihr habt gefragt, ich habe es geändert. Ab heute gilt:\"",
hook: "„Ihr habt gefragt, ich habe es geändert. Ab heute gilt:“",
format: "Talking Head", saeule: "Community", stufe: "profi",
text: "Eine Änderung, die aus der Community kam, mit Nennung derer, die sie angestoßen haben. "
+ "Mitreden zu dürfen ist der stärkste Grund zu bleiben." },
{ schluessel: "wir-machen-das-zusammen", titel: "Wir machen das zusammen",
hook: "„Wenn wir das diese Woche schaffen, mache ich Folgendes:\"",
hook: "„Wenn wir das diese Woche schaffen, mache ich Folgendes:“",
format: "Gemeinsames Ziel", saeule: "Community", stufe: "profi",
text: "Ein Ziel mit Frist und einer Belohnung, die du wirklich einlöst. "
+ "Ein Versprechen, das nicht gehalten wird, kostet mehr als es gebracht hat." },
{ schluessel: "mein-moderator-stellt-sich-vor", titel: "Mein Moderator stellt sich vor",
hook: "„Ihr kennt den Namen. Hier ist der Mensch dahinter.\"",
hook: "„Ihr kennt den Namen. Hier ist der Mensch dahinter.“",
format: "Interview", saeule: "Community", stufe: "meister",
text: "Wer im Chat für Ordnung sorgt, bekommt ein Gesicht. Das schützt ihn – "
+ "gegen einen Namen schimpft man leichter als gegen einen Menschen." },
/* ---- Eigenwerbung (10 %) ---- */
{ schluessel: "dreissig-minuten-vorher", titel: "30 Minuten vorher",
hook: "„In einer halben Stunde geht es los – und heute passiert Folgendes:\"",
hook: "„In einer halben Stunde geht es los – und heute passiert Folgendes:“",
format: "Ankündigung", saeule: "Eigenwerbung", stufe: "anfaenger",
text: "Ein kurzes Video 30 bis 60 Minuten vor dem Start. Es bündelt die, die ohnehin kommen "
+ "wollten – und ein voller Start zieht neue Zuschauer nach. Eine Sache nennen, nicht drei." },
{ schluessel: "warum-ich-heute-live-gehe", titel: "Warum ich heute live gehe",
hook: "„Heute ist ein Grund da, und der ist nicht ‚weil Dienstag ist‘.\"",
hook: "„Heute ist ein Grund da, und der ist nicht ‚weil Dienstag ist‘.“",
format: "Talking Head", saeule: "Eigenwerbung", stufe: "fort",
text: "Ein Anlass macht aus einem Termin ein Ereignis. Auch ein kleiner reicht: "
+ "ein neues Spiel, ein Gast, eine offene Frage von letzter Woche." },
{ schluessel: "mein-kanal-in-fuenfzehn-sekunden", titel: "Mein Kanal in fünfzehn Sekunden",
hook: "„Fünfzehn Sekunden, dann weißt du, ob das hier für dich ist.\"",
hook: "„Fünfzehn Sekunden, dann weißt du, ob das hier für dich ist.“",
format: "Kurzvorstellung", saeule: "Eigenwerbung", stufe: "profi",
text: "Für wen, worum, wann. Fest angeheftet, damit neue Zuschauer nicht raten müssen. "
+ "Alle paar Monate neu drehen – ein Kanal von vor einem Jahr bist du nicht mehr." },
+1 -1
View File
@@ -93,7 +93,7 @@ const EINLEITUNG = {
},
modi: {
was: "Schön, dass du da bist. Hier findest du alles für deinen Tag.",
dazu: "Unter „Aufgaben\" steht, was gerade für dich dran ist — du "
dazu: "Unter „Aufgaben“ steht, was gerade für dich dran ist — du "
+ "nimmst an, was du schaffst, und sagst ab, was nicht geht. Eine "
+ "Absage ist völlig in Ordnung, schreib einfach kurz warum.",
},