Mit Twine und Chapbook ins Wunderland (reloaded)

Twine
Tweego
Chapbook
Interactive Fiction
Spieleprogrammierung
Alice
Autor:in

Jörg Kantel

Veröffentlichungsdatum

8. April 2026

Ich möchte eine lang gehegte und lang angekündigte Idee realisieren und meine Reise ins Wunderland mit Twine und dem Storyformat Chapbook, die ich im August 2023 schon einmal (Teil 0.0, Teil 0.1, Teil 0.2) unternommen hatte, wieder aufnehmen und daraus ein Tutorial basteln. Grund für dieses Reloading ist zum einen, daß ich mittlerweile mehr über das Storyformat Chapbook gelernt habe und es in der akutellen Version auch ein paar Neuerungen gibt, aber zum anderen auch, daß ich dieses Tutorial nun mit Bildern aufpeppen kann, die von einer gekünstelten Intelligenz meines Vertrauens (in diesem Fall Nano Banana 2) generiert wurden. Denn seit Sommer 2023 hat die bildgenerierende Künstliche Intelligenz – damals noch in den Kinderschuhen – gewaltige Fortschritte erzielt.

Das Tutorial geht davon aus, daß Ihr entweder Twine auf Eurem Desktop-Rechner installiert habt oder wißt, wie die Online-Version von Twine zu bedienen ist (die Bedienung ist in beiden Fällen gleich). Da die Online-Version Eure Ergebnisse jedoch nur im Browser-Cache vorrätig hält, empfiehlt sich ein regelmäßiges Abspeichern entweder als HTML- (Build > Als Datei veröffentlichen) oder als Twee-Datei (Build > Exportiere als Twee), damit Eure Ergebnisse nicht versehentlich im Daten-Nirwana verschwinden.

Als erstes legt Ihr auf dem Startbildschirm von Twine unter Geschichte > Neu eine neue Geschichte an. Ich habe sie »Alice im Reich der Ringe« genannt, aber das könnt Ihr nach Belieben verändern (Geschichte > Umbenennen).

Mit einem Doppelklick öffnet Ihr die Geschichte und seht die erste Passage. Passagen sind die einzelnen Abschnitte Eurer Geschichte, auf die Ihr verlinken könnt und in denen Ihr Eure (nichtlineare) Geschichte erzählt. Ich habe die (bisher erste und einzige Start-) Passage »start« genannt und die kleine, grüne Rakete zeigt an, daß hier Eure Geschichte beginnt. Falls sie nicht vorhanden ist, unter Abschnitt auf Beginne die Geschichte hier klicken.

Ein Doppelklick auf die Passage öffnet ein Editorfenster, indem Ihr den Text dieser Passage eintragen oder editieren könnt. Falls Ihr das Storyformat der Geschichte noch nicht auf Chapbook umgestellt habt, sieht das Editorfenster unter Umständen noch leicht anders aus.

Die Storyformate könnt Ihr unter Twine > Geschichtsformate umstellen. Der Default zur Zeit ist Harlowe 3.3.x, für dieses Tutorial stellt aber bitte Chapbook 2.3.0 (oder größer) ein. Wenn das Storyformat einmal festgelegt ist, seid ihr für diese Geschichte daran gebunden, da die verschiendenen Storyformate bis auf wenige Befehle eine komplett unterschiedliche Syntax aufweisen. Bei einer nachträglichen Änderung des Storyformats müsst Ihr also sämtliche bisher erstellten Passagen ändern.

Jetzt könnt Ihr aber endlich mit der Geschichte beginnen. Öffnet daher mit einem Doppelklick die Startpassage und gebt folgenden Text ein:

Es war ein sonniger Tag. Alice schlenderte gedankenverloren durch das Wunderland. Sie 
hatte sich ein wenig verirrt. Plötzlich materialisierte sich auf dem Dach der alten 
Ruine am Eingang des Wunderlandes die Grinsekatze.

Alice fragte sie: »Würdest Du mir bitte sagen, wie ich von hier aus weitergehen soll!«

Die Grinsekatze grinste, wie das Grinsekatzen nun mal so tun: »Das hängt zum großen Teil 
davon ab, wohin Du möchtest. Aber ich will Dir helfen: Geradeaus geht es zum Haus der 
Herzogin, links zur Teeparty des verrückten Hutmachers und rechts triffst Du die kiffende 
Raupe auf ihrem Pilz.«

Wegen der besseren Lesbarkeit habe ich den Text umgebrochen. Chapbook folgt in Formatierungsfragen im Großen und Ganzen der Markdown-Syntax, daher werden einfache Zeilenumbrüche ignoriert, während doppelte Zeilenumbrüche einen neuen Absatz erzeugen.

Wir wollen Bilder

Alice fing an sich zu langweilen; sie saß schon lange bei ihrer Schwester am Ufer und hatte nichts zu tun. Das Buch, das ihre Schwester las, gefiel ihr nicht; denn es waren weder Bilder noch Gespräche darin. »Und was nützen Bücher,« dachte Alice, »ohne Bilder und Gespräche?«

Die Geschichte ist bisher ja recht schön erzählt, aber sie besitzt ein großes Manko: Denn was sind Geschichten ohne Bilder?

Doch das Verhältnis von Twine zu Bildern (und anderen Mulitmediadateien wie Musik, Sound oder Filmen) war von Anfang an ein schwieriges. Denn Twine war ursprünglich entworfen, um textbasierte, interaktive Abenteuer zu erzählen. Bilder waren da nicht vorgesehen. Doch das Publikum wollte – wie Alice – Bilder und so haben sich zwei mehr oder weniger inkompatible Lösungen gefunden:

Lösung 1: Bilder online einbinden

Der erste Ansatz ist, die Multimediadateien online auf einem Server abzulegen, und sie dann per HTTP(S) einzubinden. Der Vorteil dieser Lösung ist, daß die Bilder – eine Online-Anbindung vorausgesetzt – immer von Twine gefunden werden, egal ob die Twine Story in Twine (im Test-Modus) aufgerufen wird, oder ob sie standalone läuft. Jedoch hat diese Methode auch zwei gewichtige Nachteile. Der erste Nachteil: Es ist Euer Server, auf dem die Daten liegen, Ihr zahlt für die Bandbreite. Und zweitens: Ihr müßt zwingend online sein, auch wenn Ihr Euer Spiel entwickelt. Ein Schreiben oder Spielen am Strand ist damit in der Regel nicht möglich.

Außerdem hat sich hier noch eine böse Unsitte entwickelt, die man leider häufig auch Twine-Tutorials findet. Dort wird dann einfach mit einer Bildersuchmaschine ein passendes Bild gesucht. Ist dieses Bild gefunden, wird die URL kopiert und die Datei ohne Rücksicht auf Verluste vom fremden Server in die eigene Geschichte eingebunden.

Dieses Hotlinking genannte Verfahren ist aus mehreren Gründen eine Sünde: Erstens, wenn man sich nicht um die Bildrechte kümmert, gerät man dabei leicht in die Fallstricke einer Urheberrechtsverletzung und das kann teuer werden. Zweitens zahlt der Serverbetreiber und nicht Ihr die Kosten für den Datentransfer. Das macht ihn sicher nicht glücklich. Und drittens habt Ihr keine Kontrolle über die Daten. Auch ich habe schon einmal eines meiner (eigentlich harmlosen und unter einer freien Lizenz stehenenden) Photos einer Berliner Touristen-Attraktion gegen das Bild einer leicht bekleideten Dame ausgetauscht, nachdem ich bemerkt hatte, daß irgendein Dödel dieses Bild ungefragt per Hotlinking in seine dusselige Kommerzseite eingebunden hatte.

Lösung 2: Daten lokal einbinden

Die zweite Lösung ist, die Daten lokal einzubinden. Dafür legt man sich am sinnvollsten unterhalb der eigentlichen Story-Datei (Beispiel: story.html) ein Verzeichnis (oder mehrere Vereichnisse) an, die die Asset-Dateien beinhalten. Das kann dann beispielsweise so aussehen:

- story.html
- images
  - image01.jpg
  - image02.jpg
- audio
  - song01.mp3

Wenn dann ein Bild in eine Twine-Story per relativer URL eingebunden ist, in Chapbook zum Beispiel mit:

{embed image: 'images/image01.jpg', alt: 'Mein super-duper Bild'}

Dann findet Eure Twine-Story nach dem Publizieren das Bild auch, unabhängig davon, ob sie lokal oder über eine Webverbindung aufgerufen wurde.

Der Zusatz »nach dem Publizieren« weist auch gleich auf den größten Nachteil dieser Methode hin: Wird die Geschichte innerhalb von Twine gestartet (sei es über den Test- oder über den Play-Button), dann findet Twine Eure Assets nicht. Das liegt daran, daß Twine die Story temporär auf eine völlig obskure und nicht nachvolltiehbare URL hinausschreibt, beispielsweise auf (gekürzt)

file:///private/var/folders/x3/…/T/52f32371-9e39-4952-a4d8-6ee9f02e7df4.html

und wo soll das arme Twine da Eure Assets finden?

Der größte Vorteil dieser Methode ist allerdings der: Ist Eure Story mal publiziert, dann läßt sich die Datei mitsamt den Asset-Verzeichnissen entweder als .zip-Datei oder auch unkomprimiert auf jeden Server oder Dienst Eurer Wahl hochladen (zum Beispiel auf Itch.io) oder als Email an Eure Freunde verschicken. Und sie können sie dann auch spielen, ohne auf eine Internetverbindung angewiesen zu sein.

Der Kompromiß: Lokaler Webserver

Nun möchte man aber gerne auch während der Entwicklung in Twine seine Bilder sehen, und sei es nur, um das Layout kontrollieren zu können. Bei mir hat sich folgende Vorgehensweise als sinnvoll herausgestellt: Auf meinem Rechnern läuft sowieso permanent ein lokaler Webserver (zur Zeit ist es TinyHost, aber auch MAMP oder XAMPP wären eine Alternative). Dort lege ich für jede Twine-Story ein Verzeichnis mit den benötigten Bildern und anderen Assets an. Diese kann ich dann nach der Lösung 1 via localhost so einbinden, als lägen sie auf einem externen Server. In Chapbook sieht das dann so aus:

{embed image: "http://localhost:8000/alice/images/bild01.jpg", alt: "Grinsekatze"}

(Mein TinyHost lauscht auf Port 8000, den Port müßt Ihr gegebenenfalls an Eure Umgebung anpassen.)

Ist die Entwicklung dann abgeschlossen und die Story kann publiziert werden, dann tausche ich per globales Suchen und Ersetzen alle absoluten, aber dennoch lokalen URLs http://localhost:8000/alice/images durch ein schlichtes images aus. Das obige Beispiel wird dann zu

{embed image: "images/bild01.jpg", alt: "Grinsekatze"}

und damit zu einer relativen URL und zur Lösung 2. Ganz besonders schlaue Entwickler exportieren ihre Twine Story erst nach Twee bevor sie die globale Ersetzung vornehmen und schreiben die Story danach dann zum Beispiel mit Tweego als HTML-Datei heraus. So bleibt die Story im Twine-Editor unverändert, sollte man doch noch einmal Änderungen vornehmen wollen oder müssen.

Die Verwendung des alt-Textes sollte in Chapbook (aber nicht nur dort, sondern eigentlich überall) obligatorisch sein, damit sich sehbehinderte Menschen von ihrem Screenreader die Bildbeschreibung vorlesen lassen können. Sollte das Bild rein dekorativen Zwecken dienen, zum Beispiel eine schöne Seitenumrandung, dann kann der alt-Text auch einfach nur aus einem leeren String bestehen:

{embed image: "asterisk.png", alt: ""}

Moderne Screenreader werden dieses Bild dann freudig ignorieren.

So, und jetzt nach der langen Vorrede die neuesten Abenteuer von Alice mit Twine und Chapbook. Sie sind nahezu identisch mit der ersten Version, nur daß sie nun mit Bildern illustriert sind. Hier der Twee-Code der ersten Passage:

{embed image: "http://localhost:8000/alice/images/start.jpg", alt: "Grinsekatze"}

Es war ein sonniger Tag. Alice schlenderte gedankenverloren durch das Wunderland. Sie 
hatte sich ein wenig verirrt. Plötzlich materialisierte sich auf dem Dach der alten 
Ruine am Eingang des Wunderlandes die Grinsekatze.

Alice fragte sie: »Würdest Du mir bitte sagen, wie ich von hier aus weitergehen soll!«

Die Grinsekatze grinste, wie das Grinsekatzen nun mal so tun: »Das hängt zum großen 
Teil davon ab, wohin Du möchtest. Aber ich will Dir helfen: Geradeaus geht es zum 
[[Haus der Herzogin->herzogin]], links zur [[Teeparty des verrückten Hutmachers->teeparty]] 
und rechts triffst Du die [[kiffende Raupe auf ihrem Pilz->raupe]].«

Der große Vorteil des embed-Inserts von Chapbook ist, daß die damit eingebundnenen Bilder responsiv sind.

Die übrigen Passagen habe ich einfach in der gleichen Art mit Bildern aufgepeppt.

Wir wollen Stil

Zum Abschluß dieses einführenden Tutorials in Twine und Chapbook möchte ich der Geschichte noch ein wenig Stil spendieren. Denn weder die rot unterstrichenen Links noch die small caps im Footer der Seite entsprechen meinem ästhetischen Empfinden.

Chapbook besitzt einen von der restlichen Passage separierten Variablen-Abschnitt. Dieser steht immer als erstes zu Beginn einer Passage und wird von der restlichen Passage durch eine Zeile mit zwei Strichen (--) getrennt. Dieser Abschnitt kann nicht nur selbstdefinierte Variablen wie has_key oder health_points aufnehmen (dazu in späteren Tutorials mehr), sondern auch Variable, die das Layout der Geschichte beeinflussen. Diese sind in der Regel in den Objekten config.style, config.header und config.footer zusammengefaßt.

Wenn man also das Aussehen eines Links beeinflussen will, kann man zum Beispiel mit der Zeile

config.style.page.link.font: "18 bold none"

erreichen, daß der Link mit der Fontgröße 18 in fett und ohne Unterstreichung dargestellt wird. Für die Farbe des Links sind die Zeilen

config.style.page.link.color: "teal-4"
config.style.page.link.active.color: "teal-4"

zuständig, die – in diesem Fall – dafür sorgen, daß ein Link in einem leichten grün dargestellt und dieses Aussehen auch nicht verändert, wenn mit der Maus über den Link gefahren wird (active gleich hover).

Ein Wort zu den Farben: Chapbook unterstützt per Default eine freie (MIT-Lizenz) Palette, die Reasonable Colors genannt wird (entwickelt von Matthew Howell). Diese besteht aus 25 benannten Farben mit je sechs Schattierungen, also zum Beispiel teal-1 bis teal-6. Eine Übersicht bietet das Chapbook-Handbuch. Wem dies nicht ausreicht, der kann natürlich auch jede andere Farbbezeichnung verwenden, die CSS versteht (von der gewohnten Hex-Notation wie zum Beispiel #0b7285 bis hin zu sehr speziellen Notationen wie beispielsweise hsla(0%, 65%, 48%, 0.75)).

Nun besitzt Chapbook aber neben dem normalen hellen (Light) Mode (schwarze Schrift auf weißem Grund) auch noch den populären dunklen (Dark) Mode (weiße Schrift auf schwarzem Grund) auf dem Ihr im Footer jeder Seite umschalten könnt. Die Einstellungen dafür werden im Objekt config.style.dark.page, also zum Beispiel:

config.style.dark.page.link.font: "18 bold none"
config.style.dark.page.link.color: "orange-3"
config.style.dark.page.link.active.color: "orange-3"

Die config-Objekte besitzen – wie alle Variablen in Chapbook – einen globalen Gültigkeitsbereich. Es ist daher in der Regel keine gute Idee, diese innerhalb einer Geschichte mehrmals zu definieren (man sollte dann wirklich genau wissen, was man tut).

Ich habe für mein Alice-Beispiel folgende config-Objekte in der Start-Passage definiert:

config.style.page.verticalAlign: "top"
config.style.page.link.font: "18 bold none"
config.style.page.link.color: "teal-4"
config.style.page.link.active.color: "teal-4"
config.style.dark.page.link.font: "18 bold none"
config.style.dark.page.link.color: "orange-3"
config.style.dark.page.link.active.color: "orange-3"
config.style.page.footer.link.font: "16 italic none"
config.style.page.footer.link.active.font: "16 italic none"
config.style.page.footer.link.active.color: "teal-4"
config.style.dark.page.footer.link.active.color: "orange-3"
config.style.page.footer.font: "16 italic"
config.footer.left: "Alice im Reich der Ringe"
--

Die erste Zeile sorgt dafür, daß der Text der Geschichte immer am oberen Seitenrand beginnt, und nicht – wie es bei Chapbook der Default ist – in der Mitte der Seite. Dadurch werden unschöne Zeilensprünge vermieden, wenn dem Text live Zeilen oder Abschnitte hinzugefügt werden.

Die Zeile config.style.page.footer.link.active.font: "16 italic none" eliminiert die small caps im Footer der Seite durch ein freundliches kursiv, die darauf folgenden Zeilen setzen die Link-Farben und den Link-Stil jeweils für den hellen und den dunklen Mode.

Eine Besonderheit sind die beiden letzten Zeilen, in denen festgelegt wird, daß die Zeichenfolge Alice im Reich der Ringe links im Footer jeder Seite in 16 Punkt kursiv erscheint.

Welche config-Objekte existieren und mit welchen Default-Werten sie vorbelegt sind, könnt Ihr nachschauen, wenn Ihr in der Backstage View der Testumgebung unter dem Reiter Stage den Button Show Defaults ankreuzt. Alle diese Werte können von Euch bei Bedarf überschrieben werden.

Ich habe das kleine Tutorial sowohl als HTML-Datei wie auch als Twee-Datei mit allen Assets auf meinem GitHub-Account hochgeladen. Falls Ihr damit spielen wollt, müsst Ihr den Pfad zu den Bildern gegebenenfalls noch anpassen.

Und für die ganz ungeduldigen unter Euch, die einfach nur spielen wollen, habe ich die Geschichte auch in diese Seite eingebunden:



Habt Spaß damit …