Ins Stammbuch geschrieben: Kodiert mit der Auszeichnungssprache TEI

Autorin: Janica Kuhr


Wie kodiere ich einen Stammbucheintrag mit XML-TEI und welchen Nutzen hat die Anwendung dieser Mark-Up-Language bei der Erschließung des Eintrags für die Forschung? Mit diesen Fragen befasst sich dieser Beitrag.

Inhalt

  1. Was ist ein Stammbuch?
  2. Was ist TEI?
  3. Kodierung des “Werther-Stammbuchs” mit TEI
  4. Ausblick

1. Was ist ein Stammbuch?

Zum Abschied bekam ich ein Album Amicorum – in Holland, Deutschland und in den skandinavischen Ländern ist das eine beliebte Sitte. Man geh mit diesem Buch zu einem Freund, der etwas Selbsterfundenes hereinschreibt oder einen Ausspruch irgendeines Autors, und seinen Namen daruntersetzt; wenn er kann, zeichnet er noch etwas hinzu. So hat man etwas mit dessen Hilfe man sich an seine Freunde erinnern kann. Keine schlechte Idee, aber auch ein bisschen skurril.1

James Boswell

Den meisten von Ihnen dürfte der von James Boswell 1764 in seinem Journal beschriebene Brauch aus Kindheitstagen bekannt sein, denn beim hier erwähnten Album Amicorum – auch Stammbuch genannt -, handelt es sich um ein frühes Poesiealbum. Im Gegensatz zu heute waren jedoch meist Erwachsene, die als Stammbuchhalter bezeichnet werden, die Besitzer dieser Alben, die sie auch auf Reisen mit sich trugen.

Entstanden ist diese Tradition Mitte des 16. Jahrhundert in Wittenberg, als es Mode wurde, die Autographen der Reformatoren um Luther zu sammeln. Anfangs vor allem unter Studenten Anklang findend, waren die Stammbücher später in fast allen Gesellschaftsschichten beliebt und erfreuten sich im Besonderen in Deutschland bis Mitte des 20 Jahrhunderts gesellschaftlicher Wertschätzung. 2

Stammbücher können in verschiedenen Disziplinen als wertvolle Quelle dienen. So geben sie Auskunft über die Studienorte und Reiserouten sowie die sozialen Netzwerke ihrer Eigentümer. 3

Ferner lassen sich Rückschlüsse über die Alltagskultur ziehen und sie fungieren als Zeugnisse der Wissenschaftsgeschichte und Literaturhistorie. Für Sprachwissenschaftler sind die Alben inbesondere wegen der Vielfalt der Sprachen, in denen die Beiträge verfasst sind, von Interesse.4

Viele Bibliotheken und Archive sind heute im Besitz von Stammbüchern. Die weltweit größte Sammlung stellt die der Herzogin Anna Amalia Bibliothek mit über 1900 dieser Freundschaftsbücher dar.

Zentral für die Einrichtungen ist es dabei, die Erforschung ihrer Sammlungen zu ermöglichen. Doch wie soll das realisiert werden? Neben der zunehmenden Digitalisierung rückt auch eine tiefergehende Erschließung der Alben in den Fokus. So kann beispielsweise im Katalog der Herzogin Anna Amalia Bibliothek seit einiger Zeit nach Einträgen, Einträgern, Erscheinungsorten und Erscheinungsjahren der Stammbücher recherchiert werden. Die UB Tübingen wiederum stellt Transkriptionen ihrer Freundschaftsbücher zur Verfügung, die mit TEI kodiert wurden.

2. Was ist TEI?

TEI, kurz für “Text Encoding Initiative”, ist ein Dokumentenformat, das auf der Markup-Language XML basiert und der Auszeichnung von Texten dient. Beschrieben wird es in den TEI Guidelines. Neben dem Markup von textgestalterischen bzw. strukturellen Elementen, wie beispielsweise Absätzen, Zeilenumbrüchen oder der Position einer Illustration, können auch semantische Auszeichnungen vorgenommen werden. Hierzu zählt etwa die Kennzeichnung von Personennamen oder Orts- und Datumsangaben. TEI stellt heute den De-facto-Standard bei der Textkodierung dar und kommt daher bei der Erstellung von Digitalen Editionen regelmäßig zum Einsatz.5

Während jedoch beispielsweise mit TEI erstellte Briefeditionen häufiger vorkommen, sind – mit Ausnahme des Tübinger Projekts – mittels TEI kodierte Stammbucheinträge bislang sehr rar gesät.

3. Kodierung des “Werther-Stammbuchs” mit TEI

Welche Vorzüge die Kodierung von Stammbucheinträgen  mit TEI für die Forschung mit sich bringt und wie bei der Auszeichnung vorgegangen werden kann, soll daher nachfolgend exemplarisch anhand TEI-kodierter Eintragungen aus dem auch als „Werther-Stammbuch“ bezeichneten Album von Ludwig Schneider (1750-1826), einem Juristen, veranschaulicht werden.

Digitalisat der Titelseite des "Werther-Stammbuchs" mit einer Widmung von Ludwig Schneider an die Einschreiber.Abbildung 1: Titelseite des “Werther-Stammbuchs”
. © Freies Deutsches Hochstift / Frankfurter Goethe-Museum, Hs-31210/Stb. 92

Den inoffiziellen Titel “Werther-Stammbuch” trägt es, da es einen deutlichen Bezug zu Goethes Aufenthalt in Wetzlar im Sommer 1772 aufweist, als dieser die Bekanntschaft mit Charlotte Buff, dem Vorbild für Werthers Lotte sowie deren Verlobten Johann Christian Kestner machte. Von allen drei Personen finden sich Einträge im Stammbuch.6

Kodierung des Stammbucheintrags von Christian Albrecht von Kielmannsegg

Digitalisat des Stammbucheintrags von Christian Albrecht von Kielmannsegg.
Abbildung 2: Stammbucheintrag von Christian Albrecht von Kielmannsegg. © Freies Deutsches Hochstift / Frankfurter Goethe-Museum, Hs-31210/Stb. 92

Wie auch anhand der von Christian Albrecht von Kielmannsegg, ebenfalls Jurist und Jugendfreund Goethes, gestalteten Seite (Abbildung 2) deutlich wird, weisen Stammbucheinträge, die als Inskriptionen bezeichnet werden, typischerweise eine Zweiteilung auf. Auf eine im weiteren Sinn poetische Textpassage folgt in der Regel eine Widmungspassage, die aus immer wiederkehrenden Strukturelementen besteht.

Auszeichnung der Widmungspassage

Unter „Adressierung“ fallen alle Elemente, die Informationen über den Stammbuchhalter enthalten. Je nach Charakter der Beziehung kann hier die namentliche Nennung variieren. Des Weiteren kann sie durch Statusangaben angereichert werden.7

Die Elemente der „Motivierung“ und „Charakterisierung“ sind oftmals nur schwer voneinander abzugrenzen, da sie häufig fließend ineinander übergehen. Während die Komponente der Motivierung den Fokus auf den Schreibanlass legt, definiert sich die Charakterisierung dadurch, dass auf die vorangegangene Textpasssage zurückverwiesen wird. Der Stellenwert des Textteils wird hervorgehoben und Aussagen über seine Funktion getroffen.8

Den Abschluss der Passage bildet in der Regel eine sogenannte Sprachhandlungsformel, die das Verfassen des Stammbucheintrags meist als „schenken“, „widmen“, „sich empfehlen“, näher definiert.9

Dieser charakteristische Aufbau lässt sich durch TEI nachbilden. Wie das Codebeispiel zum Eintrag von Kielmannsegg zeigt, wurde der eigentliche Text als <div> (Textabschnitt) getaggt, während die Widmungspassage mit dem Element <closer> ausgezeichnet wurde, das aus der Briefedierung stammt.

[C]loser> fasst Grußformeln, Datumszeilen und ähnliche Phrasen zusammen, die am Ende eines Abschnitts stehen.10

   </teiHeader>
   <text type="Stammbucheintrag">
      <body>

         <div type="Dramenverse">
            <cit>
               <quote xml:id="Fußnote1">
                  <l>Am be&#383;ten i&#383;t, und wahr&#383;ten der mein Freund,</l>
                  <l>Der warm, nicht heiß das Gute, das ich habe;</l>
                  <l>Der &#383;treng nicht, doch genau den Fehl auch &#383;ieht.</l>
                  <l>Hat die&#383;er Freund ein Herz der Redlichen,</l>
                  <l>So liebt er mich, wie ich geliebt mag &#383;ayn.</l>
               </quote>
               <bibl>
                  <author ref="http://d-nb.info/gnd/118563386" rend="underlined"
                  >Klopstock</author>.</bibl>
            </cit>
         </div>
         <closer>
            <salute rend="right"><seg type="Adressierung">dem Herrn Be&#383;itzer die&#383;es
                  Buchs</seg>
               <seg type="Schreibhandlungsformel">em-<lb/>pfiehlt &#383;ein Andenken be&#383;tens
                  und gehor&#383;am&#383;t.</seg></salute>
            <signed rend="right">
               <persName ref="http://d-nb.info/gnd/116157372"><forename><choice>
                        <abbr>C.</abbr>
                        <expan>Christian</expan>
                     </choice></forename><surname> Kielmannsegg</surname></persName> aus <placeName
                  ref="http://d-nb.info/gnd/4038197-3">Meklenburg</placeName></signed>
            <dateline rend="left"><placeName ref="http://d-nb.info/gnd/4065878-8"
                  >Wetzlar</placeName>, den <date when="1773-05-16">16ten May 1773</date></dateline>
         </closer>

      </body>
      <note type="editorial" target="#Fußnote1">Die Verse wurden dem Trauerspiel <name type="work"
            >David.Ein Trauerspiel</name> von <persName ref="http://d-nb.info/gnd/118563386"
               ><forename>Friedrich Gottlieb</forename><surname> Kloppstock</surname></persName>
         entnommen.</note>
   </text>
</TEI>

Innerhalb dieses Abschnitts wiederum wurden die Adressierung und Sprachhandlungsformel näher spezifiziert. Zunächst wurden sie durch das Element <salute> als Bestandteil der Grußformel ausgewiesen und anschließend anhand des <seg>-Elements (Segment) in Verbindung mit dem type-Attribut eindeutig als Addressierung (<seg type=”Adressierung”) bzw. Schreibhandlungsformel (<seg type=”Schreibhandlungsformel”) gekennzeichnet.

Als problematisch kann sich in diesem Zusammenhang die Tatsache erweisen, dass XML keine Überlappungen zulässt. So ist es grundsätzlich möglich, dass Textteile sowohl Bestandteil der Motivierung als auch der Charakterisierung sind und sich darüber hinaus gleichzeitig der Sprachhandlungsformel zuordnen lassen. Als pragmatische Lösung hierfür bietet sich jedoch an, nur die jeweils charakteristischen Worte den entsprechenden Bestandteilen der Widmung zuzuordnen.

Der Name bzw. die Unterschrift des Einträgers wird als <signed> (Unterschrift) getaggt und als <persName> – unterteilt in <fore- und surname> – erfasst, während Orts- und Datumsangabe zunächst unter <dateline> zusammengefasst und dann durch <placeName> bzw. <date> gekennzeichnet werden. Durch die Verwendung des when-Attributs in Verbindung mit <date> wird das Datum zusätzlich noch in maschinenlesbarer und normierter Form aufgenommen. Das <signed>-Element dient dazu, dass der Name des Einträgers später eindeutig maschinell herausgefiltert werden kann, da an mehreren Stellen im Stammbucheintrag Personennamen in unterschiedlichen Funktionen vorkommen können. Eine Besonderheit stellt hier die Auszeichnung des Namens dar. Kielmannsegg hat seinen Vornamen mit C. abgekürzt, was durch das Element <abbr>, Abbrevation kodiert wird. TEI lässt es jedoch zu, durch das Element <expan> (Expansion) gleichzeitig den ermittelten, vollen Namen anzugeben.

Auch ein weiterer großer Vorteil der Verwendung von TEI wird in diesem Zusammenhang deutlich. So ist es durch das ref-Attribut möglich auf Normdaten zu referenzieren. Konkret wurde hier mittels des Attributs bei <persName> der GND-Eintrag des Verfassers Christian Kielmansegg verlinkt. Auch bei den Entitäten Eintragungsort und Herkunftsort des Verfassers, ebenfalls durch <placeName> ausgezeichnet, wurde ein Link zum GND-Eintrag aufgenommen.

Neben der eindeutigen Identifizierung kann diese Erfassung der Normdaten der Erforschung und Visualisierung von Personennetzwerken oder der Sichtbarmachung der Wege und Aufenthaltsorte des Stammbuchhalters sowie der Einträger dienen.

Dazu ein Beispiel aus der Goethe-Forschung: Lange ging man davon aus, dass Johann Caspar Goethe, der Vater des berühmten Dichters, zu einem bestimmten Zeitpunkt Berufspraxis in Wien sammelte, da er dies in einem Bittgesuch an Kaiser Karl zu Protokoll gegeben hatte. Anhand von zwei Stammbucheinträgen konnte man jedoch nachweisen, dass er tatsächlich aber -mutmaßlich im Rahmen einer Bildungsreise – in Augsburg weilte und auch, dass er nicht alleine reiste, da sich eine weitere Person, Johann Georg Cocceji, jeweils am selben Tag wie Goethe in beide Stammbücher eintrug. 11

Die Position der Grußformel und Datumszeile auf der Seite, die sich in vielen Stammbucheinträgen wiederfindet, lässt sich durch das Attribut rend=”right” oder rend=”left” ausdrücken, z. B. <dateline rend=”left”>.

Auszeichnung der Textpassage

Werfen wir nun einen Blick auf die der Widmung vorangestellte Textpassage. Typischerweise besteht diese aus wenigen Gedichtversen oder knappen Prosatexten, die zum Nachdenken angeregen, Einsichten vermitteln oder an das Befolgen bestimmter Maxime appellieren.12 Im Regelfall handelt es sich dabei um bereits bestehende Texte, die wortgenau oder leicht verändert, mit oder ohne Angabe des Urhebers, zitiert werden.13

Auch Kielmansegg bedient sich eines bereits vorhandenen Textes. So zitiert er ein Werk Friedrich Gottfried Kloppstocks. Der Zitatcharakter des Elements wurde durch das Element <quote> deutlich gemacht.

Da der Einschreiber außerdem Kloppstock als geistigen Schöpfer angegeben hatte, wurden diese Quellenangabe und das Zitat zusätzlich durch das Elternelement <cit> (cited quotation) ausgezeichnet. So heißt es in den TEI:

Dabei wird der gesamte Zitatblock, inklusive Zitat und Quelle, mit dem dafür vorgesehenen <cit>-Element umschlossen. Die Quellenangabe wird mit dem <bibl>-Element kodiert, das […] unstrukturierte bibliografische Angaben repräsentiert.14

Innerhalb der Quellenangabe wurde Kloppstock mit <author> getaggt und der GND-Normdatensatz verknüpft. In einem editorischen Stellenkommentar <note>, der über eine xml:ID und das Attribut target mit der referenzierten Passage verknüpft ist, können zusätzliche Informationen zum Text festgehalten werden. In diesem Fall wurde darauf hingewiesen, dass die Verse dem Trauerspiel “David” von Kloppstock entnommen sind.

Das Zitat wiederum wurde zusätzlich mit dem Element <div> ausgezeichnet , was erst einmal recht allgemein für Textabschnitt steht. Durch die Verwendung des Attributs type, konnte jedoch eine Aussage über die Gattungszurordnung, hier type=”Dramenverse” getroffen werden.

An dieser Stelle wird deutlich, dass die TEI-Kodierung nicht nur in Bezug auf die personengeschichtliche Forschung, sondern auch im Hinblick auf die in den letzten Jahren stärker werdende Beschäftigung mit der literarischen Gestaltung der Stammbucheinträge Potential bietet. So werden intertextuelle Verweise sichtbar und eine Auswertung der Kodierung lässt beispielsweise Aussagen über die Häufigkeit der Zitierung bestimmter Autoren oder die Verwendung von Textgattungen zu. Angesichts der wachsenden Zahl an Werknormdaten in der Gemeinsamen Normdatei wäre es in diesem Zusammenhang zukünftig wünschenswert, auch auf diese zu verweisen. Im Fall des Kloppstockschen Trauerspiels war leider kein Normdatensatz vorhanden.

Auch Besonderheiten bei der textlichen Gestaltung können ausgezeichnet werden. So wird die Unterstreichung des Namen Kloppstock durch das Attribut rend=”underlined” ausgedrückt und die verwandten langen s („ſ“) der Kurrentschrift werden durch Unicode dargestellt.

Kodierung des Stammbucheintrags von Dietz Kays
Digitalisat der Bildbeigabe des Stammbucheintrags von Dietz Kays
Abbildung 3: Bildbeigabe des Stammbucheintrags von Dietz Kays. © Freies Deutsches Hochstift / Frankfurter Goethe-Museum, Hs-31210/Stb. 92

Neben den Texten finden sich auch immer wieder Illlustrationen in den Stammbüchern. Bei der Erstellung bediente sich der Einschreiber den unterschiedlichsten künstlerischen Techniken, die von Bleistift- Buntstift-, Kohle- und Tuschezeichnungen über Aquarellmalereien und Gouache zu Druckgrafiken reichen. Ebenso vielfältig ist auch die Wahl der Motive. So finden sich darunter zum Beispiel Wappenzeichnungen oder Porträts, aber auch Bildgegenstände, die sich auf den Text, den Eigentümer des Stammbuchs oder sein Verhältnis zum Einträger beziehen.15

Auszeichnung der Bildbeigabe

Auch diese bildlichen Elemente können durch TEI ausgezeichnet werden. So wurde die Vogel-Zeichnung (Abbildung 3) in dem hier in Auszügen vorgestellten kodierten Eintrag von Dietz Kayß zunächst mittels <div type=”Bildbeigabe”> getaggt und zusätzlich mit dem Element <figure> als Abbildung ausgezeichnet. Durch das type-Attribut wurde sie näher als Tuschezeichnung klassifiziert. Mittels des Elements <graphic> in Kombination mit dem Attribut url kann die Quelle angegeben werden. <FigDesc> (description of figure) ermöglicht eine detailllierte Beschreibung des Bildinhalts.

Die Kodierung der graphischen Bestandteile des Eintrags erlaubt es auch hier, die Daten später gezielt maschinell auszulesen, um beispielsweise Aussagen über die Verwendungshäufigkeit von Techniken oder Motiven zu treffen.

 </teiHeader>
   <text type="Stammbucheintrag">
      <body>
         <pb n="60"/>
         <div type="Bildbeigabe">
            <figure type="Tuschzeichnung">
               <graphic url="bildconcordia.jpeg"/>
               <figDesc>Bei der Abbildung handelt es sich um die Zeichung eines Vogels im Flug,
                  mutmaßlich einer Taube, der ein Spruchband mit der Aufschrift "Concordia" im
                  Schnabel hält. In der rechten oberen Ecke des Bildes ist eine strahlende Sonne mit
                  grimmigen Gesichtsausdruck zu sehen. Augenscheinlich wurde die Zeichnung mit
                  brauner Tinte angefertigt.</figDesc>
            </figure>
         </div>
 

Auszeichnung der Textkomponente

Digitalisat des Textteils des Stammbucheintrags von Christian Albrecht von Kielmannsegg
Abbildung 4: Textteil des Stammbucheintrags von Dietz Kayß. © Freies Deutsches Hochstift / Frankfurter Goethe-Museum, Hs-31210/Stb. 92

Die Auszeichnung der Textkomponente dieser Inskription (Abbildung 4) wiederum zeigt, dass TEI auch der Erforschung, in welchen Sprachen die Stammbucheinträge verfasst wurden, Rechnung trägt. So wurde das erste Zitat, bei dem es sich um eine Gnome – also einen Sinnspruch – handelt, mit dem Attribut xml:lang und dem Sprachcode “la” ausgezeichnet, um auszudrücken, dass es, abweichend vom restlichen Text, in lateinischer Sprache vorliegt. In diesem Zusammenhang wurde auch durch @rend=”latintyp” die Verwendung der lateinischen Schrift gekennzeichnet.

Bei den darunter befindlichen Versen konnte durch das <rhyme>-Element zunächst deutlich gemacht werden, dass es sich um einen Reim handelt und mittels des Attributs label wurde zusätzlich das hier verwendete Reimschema getaggt.

Als problematisch erwies sich die Kodierung des Studentenordens im Beispiel. Eigentlich eher ein Schriftsymbol – und damit textuelles Element – wurde er dennoch in Ermangelung einer spezifischeren Auszeichnungsmöglichkeit als Abbildung getaggt.

  
         <pb n="61"/>
         <div type="Gnome">
            <p><quote xml:lang="la" rend="latintyp" xml:id="Fußnote1">Amicus certus in re incerta
                  cernitur</quote></p>
         </div>
         <div type="Gnome">
            <quote>
               <lg type="rhyming_couplet">
                  <l>Gute Freunde in der <rhyme label="a">Noth</rhyme></l>
                  <l>gehen tausend auf ein <rhyme label="a">Loth</rhyme></l>
               </lg>
            </quote>
         </div>
         <closer>
            <salute rend="right">
               <seg type="Adressierung">
                  <choice>
                     <abbr>HochEdelgeb&#x2113;</abbr>
                     <expan>Hochedelgeborener</expan>
                  </choice> Herr und <choice>
                     <abbr>Br.</abbr>
                     <expan>Bruder</expan>
                  </choice></seg>
            </salute>
            <salute rend="right">
               <seg type="Motivierung">Habe die Gewogenheit, und erinnere<lb/> Dich öfters Deines<lb/>
                  <choice>
                     <abbr>gehor&#383;&#x2113;</abbr>
                     <expan>gehor&#383;amen</expan>
                  </choice>
                  <choice>
                     <abbr>Dr.</abbr>
                     <expan>Dieners</expan>
                  </choice> und Freunds</seg></salute>
            <signed rend="right">
               <abbr>K.A.F.</abbr>
               <unclear reason="illegible" cert="medium"><persName><forename>Dietz</forename>
                     <surname>Kayß</surname></persName></unclear>. <abbr>Not.</abbr></signed>
            <dateline rend="left"><placeName ref="http://d-nb.info/gnd/4020989-1">Giesen</placeName><lb/>
               <date when="1771-03-28">28.3.1771</date>
            </dateline>
         </closer>
         <figure type="Zeichen_eines_Studentenordens" rend="left">
            <figDesc>Zeichen eines Studentenordens, enthält augenscheinlich die Zahl 1770 und ein
               C</figDesc>
         </figure>
      </body>
      <note type="editorial" target="#Fußnote1">Gnome wird <persName
            ref="http://d-nb.info/gnd/118520814"><forename>Marcus Tullius</forename>
            <surname>Cicero</surname></persName>zugeschrieben.</note>

   </text>
</TEI>

4. Ausblick

Generell stellen neben den Illustrationen auch die vielfältigen anderen Beigaben eine Herausforderung bei der Kodierung von Stammbucheinträgen mit TEI dar. Mitunter findet man Papierschnitte, Stickarbeiten, getrocknete Blumen, Siegelabdrücke, Musiknoten, aber auch Haarlocken sind keine Seltenheit.16

Während für die Kodierung von Siegeln mit <seal> ein spezifisches Element zur Verfügung steht und auch Musiknoten innerhalb eines Textes sich über <notatedMusic> taggen lassen bzw. für Musiknoten mit den MEI sogar eigene Codierungsrichtlinien existieren, sind die TEI für die Auszeichnung der anderen (dinglichen) Objekte (zumindest bislang) nicht ausgelegt.

Auch im Hinblick darauf, dass diese Beigaben sich ebenso bei Briefen finden lassen, wäre eine Weiterentwicklung der TEI in dieser Hinsicht wünschenswert. Festzuhalten bleibt aber auch, dass diese Mark-Up-Language bereits jetzt durch die inhaltlich, formal und strukturell tiefgehende Erschließung der Einträge neue Perspektiven für die Stammbuchforschung eröffnen kann.

Zum Download als PDF-Datei stehen nachfolgend die vollständigen Kodierungen der im Text erwähnten Beispiele sowie weitere exemplarisch kodierte Stammbucheinträge bereit:

Die dazugehörigen Digitalisate sind in der Slideshow (Abbildung 5-8) zu finden.

Falls Sie noch nicht mit TEI vertraut sein sollten, diese Mark-Up-Sprache jedoch Ihr Interesse geweckt hat, finden Sie beispielsweise im Internetauftritt der Universität Bern einen ausführlichen Crashkurs und Workshop.

Quellen


1Boswell, James: Journal, hrsg. von Helmut Winter. Stuttgart 1986. Zitiert nach Linhart, Eva: Vom Stammbuch zum Souvenir d’Amité. Deutscher Schicksalsfaden. In: Schmidt, Volker [Hrsg.]: Der Souvenir : Erinnerung in Dingen von der Reliquie zum Andenken. Köln 2006, S. 202-232

2Vgl. Schlüter, Andras; Gebert, Björn: 30.000 Datensätze und neun Wochen Zeit. 17.05.2018. https://blog.klassik-stiftung.de/coding-da-vinci/, Zugriff 23.01.2022

3Vgl. Schlüter, Andras; Gebert, Björn: 30.000 Datensätze und neun Wochen Zeit. 17.05.2018. https://blog.klassik-stiftung.de/coding-da-vinci/, Zugriff 23.01.2022

4Vgl. Eberhards Karls Universität Tübingen [Hrsg.]: Stammbücher der UB Tübingen. Stand 25.01.2021. http://www.dh-profil.uni-tuebingen.de/tuebinger-stammbuecher/index.html, Zugriff 23.01.2022

5Vgl. Universität Graz. Zentrum für Informationsmodellierung in den Geisteswissenschaften [Hrsg.]: Text Enconding Initiative. 2006-2008. https://www-gewi.uni-graz.at/zim/lehre/tei.html, Zugriff 23.01.2022

6Vgl. Heumann, Konrad: Bedeutendes Stammbuch der Wertherzeit. (Unveröffentlichtes Typoskript)

7Vgl. Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 22

8Vgl. Schnabel, Werner Wilhelm: Das Album Amicorum. Ein gemischtmediales Sammelmedium und einige seiner Variationsformen. In: Kramer, Anke [Hrsg.]: Album : Organisationsform narrativer Kohärenz. Göttingen 2013, S. 213-239, hier S. 215; Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 22

9Vgl. Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 22

10Text Encoding Initiative. P5: Richtlinien für die Auszeichnung und den Austausch elektronischer Texte. Version 4.3.0. Last updated on 31st August 2021. https://tei-c.org/release/doc/tei-p5-doc/de/html/ref-closer.html, Zugriff 23.01.2022

11Vgl. Heumann, Konrad: Unterwegs nach Italien. Johann Caspar Goethes Reise nach Nürnberg und Augsburg im Jahr 1739. In: Hopp, Doris: »Goethe Pater». Johann Caspar Goethe (1710–1782). Frankfurt 2010, S. 52-61

12Vgl. Schnabel, Werner Wilhelm: Das Album Amicorum. Ein gemischtmediales Sammelmedium und einige seiner Variationsformen. In: Kramerm Anke [Hrsg.]: Album : Organisationsform narrativer Kohärenz. Göttingen 2013, S. 213-239, hier S. 215

13Vgl. Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 20

14Karl-Franzens-Universität Graz [Hrsg.]: Elektronische Repräsentation mit dem Standard der TEI

15Vgl. Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 21; Schnabel, Werner Wilhelm: Das Stammbuch : Konstitution und Geschichte einer textsortenbezogenen Sammelform bis ins erste Drittel des 18. Jahrhunderts. Tübingen 2003. S. 104

16Vgl. Bastian, Julia: «Des Menschen Herz faßt so unendlich viel» Das Stammbuch des Volrat Graf zu Solms-Rödelheim und Assenheim. Frankfurt 2013, S. 21; Schnabel, Werner Wilhelm: Das Album Amicorum. Ein gemischtmediales Sammelmedium und einige seiner Variationsformen. In: Kramer, Anke [Hrsg.]: Album : Organisationsform narrativer Kohärenz. Göttingen 2013, S. 213-239, hier S. 218


Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Content Management (Wintersemester 2021/22, Dr. Stefanie Elbeshausen) entstanden.

Die besten Beiträge stellen wir Euch hier in den nächsten Wochen nach und nach vor.

Urheberrecht im Kontext von Fan Fictions und RPGs

Beitragsbild

Autor: Simon Kugler


Wie Fan Fictions entstanden und warum sie gegen das Urheberrecht verstoßen


Wie Fan-Fiction-Autoren und RPG-Betreiber mit der geltenden Rechtslage umgehen


Wie sich die Fan-Fiction-Kultur professionalisiert und was aus dieser Entwicklung erwächst


Abschnitt 1 – Der ReichenbaChfall

Altes Konzept – modernes Phänomen

"Handschrift" by Rob van Hilten is licensed under CC BY-NC-SA 2.0
“Handschrift” by Rob van Hilten is licensed under CC BY-NC-SA 2.0

Das Weitererzählen, Verändern oder Umformen bestehender Erzählungen hat eine lange Historie und Tradition.

Im Mittelalter wurden antike Stoffe aufgegriffen und für die bestehende höfische Gesellschaft neu interpretiert und arrangiert. Auch die Artus-Sage wurde vielfach aufgegriffen und in Versform gegossen. Für die eigene Erzählung griff man dabei fast immer auf bereits bestehendes Material zurück. Alles war miteinander verwoben.

Auch Bertold Brechts berühmte Dreigroschenoper ist eine Bearbeitung eines bestehenden Werkes. Der Dramatiker ließ sich von der Beggar’s Opera aus dem Jahr 1728 inspirieren. Einige Lieder, die Brecht in seinem Stück verwendet, stammen zudem von dem spätmittelalterlichen Dichter François Villon. Brecht übernahm sie wortgetreu. Ohne Quellenangabe.[1]

Ein weiteres modernes Beispiel ist der Kosmos von H. P. Lovecraft, der noch zu seinen Lebzeiten durch Erzählungen von befreundeten Autoren, mit denen er rege korrespondierte, angereichert und erweitert wurde.

Fan Fictions und schriftbasierte Roleplaying-Games, die an ein beliebtes Buch, eine Serie oder einen Film anknüpfen, reihen sich also in eine lange Tradition der Stoffadaption ein. Was sie machen ist somit keineswegs neu. Doch aufgrund ihrer Form und der veränderten Bedingungen sind sie doch etwas vollkommen Neuartiges – ein modernes Phänomen. Ein Phänomen, das von Beginn an ein Spannungsfeld erzeugte.

Denn nach wie vor sind die meisten Fan Fictions und RPGs eigentlich illegal.

Wie sich die Fan-Fiction-Kultur entwickelte

Im Jahr 1893 stürzen zwei Männer in den Tod. Die tragische Szene ereignet sich in der Schweiz, aber sie wird vor allem in Großbritannien für große Bestürzung sorgen. Aber auch für Empörung und Unverständnis. Dabei sind die beiden zu Tode gekommenen Männer nicht einmal real. Es sind fiktive Figuren. Der eine ist der »Napoleon des Verbrechens«, der andere der vermutlich schon damals berühmteste Detektiv der Welt – Sherlock Holmes.

'The Death of Sherlock Holmes'
“‘The Death of Sherlock Holmes’ (frontispiece from The Memoirs of Sherlock Holmes, 1894)” by Toronto Public Library Special Collections. Licensed with CC BY-SA 2.0.

Arthus Conan Doyle tötet den Protagonisten seiner Detektivgeschichten und die Tat treibt seine Leser auf die Straße. Öffentlich wird der Tod der literarischen Figur betrauert. Weil Doyle erst 1903 ein Einsehen hat und Holmes von den Toten auferstehen lässt, vernetzen sich die Leser miteinander, um das Gedenken an den Detektiv lebendig zu halten.[2] Damit legen sie den Grundstein für das erste organisierte Fandom. In verlagsunabhängig publizierten Magazinen und Essays werden Figuren und Handlung besprochen, Lücken gefüllt und kontradiktorische Angaben in den Geschichten diskutiert.[3]

Die Begrifflichkeit Fan Fiction etabliert sich in den 1960ern, als das Star-Trek-Universum immer mehr Menschen in seinen Bann zieht und mit Spockanalia das erste Fanzine entsteht, in dem Fans Bilder, Kommentare und eigene Geschichten publizieren.[4]

Seitdem entstanden unzählige weitere Fandoms, basierend auf Filmen, Serien, Büchern oder Comics und sie alle fanden in den 90ern im Internet eine neue Heimat, das mit seinen Möglichkeiten der weltweiten Vernetzung, Interaktion und Publikation optimale Bedingungen für die kreative Fankultur bot.

Verbreitung im Internet

»Heute ist Fan Fiction ohne die zugrunde liegenden digitalen Praktiken der Vernetzung von Dokumenten und Akteuren kaum mehr denkbar.«

Reißmann, Klaas, Hoffmann: Fan Fiction, Urheberrecht und Empirical Legal Studies

Fan Fictions fanden zunächst über fandom-spezifische Foren und Mailinglisten Verbreitung[5], waren aber auch bald schon auf eigenständigen Plattformen zu finden. Dadurch konnten sie mitunter eine große Leserschaft gewinnen. Die größten Plattformen und Archive diese Art, wie die englischsprachigen Seiten ‘Archiv of your own’ (AO3) und ‘FanFiction.net’, haben heute Nutzerzahlen in Millionenhöhe.[3]

Durch die Vernetzung der Community entstehen ständig neue Projekte. Es kommt zu Kooperation oder inhaltlichen Crossovers, bei denen Charaktere aus verschiedenen Vorlagen aufeinandertreffen.

Fan Fictions sind aber nicht die einzige Ausdrucksform literarischer Kreativität von Fans im Internet. In forengestützten Role-Playling Games (RPGs) werden Geschichten aus Sicht einzelner Figuren kollaborativ erzählt. Als Grundlage dient dabei meist ein spezifisches Universum, das durch die verschiedenen Handlungsstränge stetig erweitert, verändert oder neu ausgestaltet wird. Durch den kollektiven Schreibprozess kommt es zu einer Verschmelzung von Autor und Leser und oft auch zu einer starken Identifizierung mit der eigenen Figur.

Die Urheberrechtsproblematik

Durch das Internet wurden Fan Fictions immer mehr zu einem Massenphänomen. Die bereits bestehende Frage, in welchem Rahmen die Nutzung von urheberrechtlich geschütztem Material in einem nicht-kommerziellen Kontext praktiziert werden kann, gewann durch diese Entwicklung neue Brisanz. Denn was im Privaten problemlos möglich ist, erhält im Internet eine ganz andere Dimension.

Sobald ein Text der Allgemeinheit zugänglich gemacht wird, und dazu zählt auch das Publizieren in Foren oder Online-Archiven, fällt er unter geltendes Recht. Und dieses besagt:

»Bearbeitungen oder andere Umgestaltungen des Werkes dürfen nur mit Einwilligung des Urhebers des bearbeiteten oder umgestalteten Werkes veröffentlicht oder verwertet werden.«

§ 23 UrHG

Dieser Schutz gilt bei literarischen Werken nicht nur für die Gesamtdarstellungen, sondern auch für einzelne Figuren, sofern deren Darstellung charakteristisch für das Werk ist. Gemeint sind damit handelnde Figuren mit Wiedererkennungswert, wie bpsw. Harry Potter oder Bella Swan, aber auch Nebenfiguren, wie Severus Snape oder Charlie Swan, Bellas Vater.

»Der Gestaltenschutz der Rechtsprechung honoriert somit die individuelle
Konzeption einer fiktiven Figur.«

Claudia Summerer: “Illegale Fans”

Allerdings gibts es unter Juristen eine differenzierte Debatte darüber, wie eng oder weit der Gestaltenschutz gefasst werden kann und sollte.[6] Für Fan-Fiction-Autoren und RPG-Autoren ist diese Uneindeutigkeit ein Unsicherheitsfaktor, da im Zweifelsfall unklar bleibt, ob bspw. bereits die Zuschreibung bestimmter Charakteristiken für eine bestimmte Figur den Gestaltenschutz berührt oder nicht.

Mit dieser Problematik befasst sich auch Rechtsanwalt Christian Solmecke in seinem Video zum Thema Urheberrecht und Fan Fiction.

 

Abschnitt 2 – Please Don’t Sue ME

Umgang mit Rechtsnormen und Schutzrechten

In der Fan-Fiction-Community (RPGs mit eingeschlossen) herrschte lange die Annahme vor, sich in einer rechtlichen Grauzone zu bewegen. Mitunter wird auch heute noch vereinzelt davon ausgegangen.

Gründe für diese Annahme waren und sind zum einen Differenzen zwischen verschiedenen nationalen Rechtsnormen, wie dem deutschen Urheberrecht und dem amerikanischen Copyright Law, aber auch einzelne Aspekte der jeweiligen Gesetze.

Das Urheberrecht unterscheidet bspw. zwischen freier Benutzung und unfreier Bearbeitung.[7] Die freie Benutzung greift immer dann, wenn ein urheberrechtlich geschütztes Werk lediglich als Inspirationsquelle verwendet wird und das neu entstandene Werk selbst urheberrechtlich schutzfähig ist. Dafür müssen beide Werke jedoch ausreichend unterschiedlich sein. Trifft dies zu, dann gilt:

»Ein selbständiges Werk, das in freier Benutzung des Werkes eines anderen geschaffen worden ist, darf ohne Zustimmung des Urhebers des benutzten Werkes veröffentlicht und verwertet werden.«

§ 24 UrhG

 

Ab wann sich zwei Werke ausreichend voneinander unterscheiden, ist allerdings nicht näher bestimmt. Es sollte daher nicht verwundern, dass die freie Benutzung von Fan-Fiction- und RPG-Autoren im Zweifelsfall weiter gefasst wurde und wird als von Urheberrechtsinhabern.

Es muss jedoch davon ausgegangen werden, dass bereits die Erwähnung charakteristischer Handlungsorte oder Nebenfiguren, selbst wenn der Rest des Werkes eindeutig eine kreative Eigenleistung darstellt, dazu führen kann, dass das gesamte Werk nicht mehr im Einklang mit dem Recht auf freie Benutzung steht.

E. L. James, Autorin von Fifty Shades of Grey, änderte aus einem ähnlichen Grund, noch bevor ihre Geschichte als Buch publiziert wurde, die Namen ihrer Protagonisten, die an Edward Cullen und Bella Swan angelegt waren, ab.

Dem Gestaltenschutz, der nicht näher definierten Trennlinie zwischen freier Bearbeitung und unfreier Benutzung, sowie weiteren rechtlichen Unsicherheiten wird durch die gängige Praxis Tribut gezollt, in einem Disclaimer auf die Rechteinhaber des Ausgangsmaterials zu verweisen und sich von allen Eigentumsansprüchen an den verwendeten Figuren und übernommenen Inhalten freizusprechen.

Diese Disclaimer, egal welcher Art, haben jedoch keine rechtliche Gültigkeit und schützen im Zweifelsfall nicht vor einer Abmahnung oder Anklage. Diese Tatsache ist auch bereits seit langem in der Community bekannt, dennoch werden Disclaimer standardmäßig verwendet, weil sie a) zum guten Ton gehören b) den Schöpfer des zugrundeliegenden Werks würdigen und c) nach außen signalisieren, dass sich die Autoren bewusst sind, dass sie ein urheberrechtlich geschütztes Werk als Grundlage für ihre eigenen Texte verwenden und es sich somit nicht heimlich “aneignen”.

Die Urheberrechtsreform

Auch die Urheberrechtsreform, die 2018 vom EU-Ministerrat auf den Weg gebracht und im März 2019 vom EU-Parlament beschlossen wurde und bis zum 07. Juni 2021 in nationales Recht umgesetzt werden muss, half nicht dabei, die bereits bestehenden Unsicherheiten auszuräumen. Zwar waren Fan-Fiction- und RPG-Autoren von der Reform allenfalls indirekt betroffen, bedingt durch den allgemeinen Aufschrei im Internet und den massiven Protest, der sich sowohl im Digitalen als auch auf der Straße formierte, wurde allerdings ein neues Bewusstsein für geltende Rechtsnormen und bestehende Probleme geschaffen.

Aber auch außerhalb der Community geriet durch die Urheberrechtsreform einiges in Bewegung. Fan Fictions wurden bspw. im Kontext der Grundsatzdiskussion über das Urheberrecht in Bezug auf Mashups und Remixes thematisiert[8] oder zum Gegenstand wissenschaftlicher Forschung.

An der Universität Siegen befasste sich eine Projektgruppe im Rahmen des Sonderforschungsbereichs “Medien der Kooperation” am Beispiel von Fan Fiction mit den sozialen und juristischen Rahmenbedingungen kooperativen und derivativen Werkschaffens im Netz. Die Projektleiterin Dr. Dagmar Hoffmann (Professorin für Medien und Kommunikation) kommt zusammen mit Dr. Wolfgang Reißmann dabei zu folgender Einschätzung:

»Zwar suggeriert die derzeitige Situation – zumindest im Bereich Fan
Fiction – eine Koexistenz der kreativen Fans, die gewisse rote Linien nicht überschreiten, und der Medienindustrie, die von weitgehender Verfolgung absieht. Dieses fragile Nebeneinander kann letztlich jedoch nicht darüber hinwegtäuschen, dass für die Fans Rechtsunsicherheit besteht und sie im Zweifelsfall, wenn ihr Handeln nicht in die Verwertungs- und Marketingstrategien der großen Medienunternehmen passt, rechtlich am „kürzeren Hebel“ sitzen.«

Selbstbestimmung in Fan-Fiction-Kulturen. In: M&K, Jahrgang 66 (2018), Heft 4.

Die beiden Forscher äußern im Weiteren ihre Hoffnung, dass die wissenschaftliche Betrachtung eine produktive Grundlage für die bestehende Auseinandersetzung bieten wird.

Derzeit zeigen sich die meisten Autoren und Verlage aufgeschlossen gegenüber dem kreativen Schaffen der Fans. Ohne eine Sicherheiten schaffende Reformierung des geltenden Urheberrechts auf nationaler Ebene bleibt die Fan-Fiction-Kultur damit aber abhängig vom guten Willen und der Duldung der Urheberrechtsinhaber.

Dass eine solche Toleranz keinesfalls selbstverständlich ist, hat die Vergangenheit gezeigt.

Abschnitt 3 – Trends und Herausforderungen

Wie Autoren die Fan-Fiction-Kultur bewerten

Zu Beginn des neuen Jahrtausends spitzte sich der Konflikt zwischen Rechteinhabern und Fan-Autoren zu. Es wurde mit Abmahnungen gedroht und vereinzelt kam es auch zu juristischen Auseinandersetzungen.[9] Einzelne Autoren ging es darum, die alleinige Deutungshoheit über ihr Schaffenswerk zu behalten, andere fürchteten Plagiate und Umsatzeinbußen durch Fan Fictions.

Die kommerzielle Verwertung von Fan Fictions und RPG-Inhalten spielte allerdings weder zum damaligen Zeitpunkt noch danach eine relevante Rolle. Auch Plagiate blieben eine absolute Seltenheit. Stattdessen erkannten große Verlage und Markeninhaber, dass die Fan-Fiction-Kultur vor allem positive Effekte hervorruft, bspw. indem sie zur Bekanntheit eines Werkes beiträgt oder für eine langfristige Kundenbindung sorgt.[9]

Das veränderte die Wahrnehmung der Fan-Fiction-Kultur, die nun weitaus positiver bewertet und auch von einigen äußerst populären Autoren, wie J. K. Rowling, Stephanie Meyer oder Terry Pratchett, als Würdigung ihrer eigenen Werke verstanden wurde. Das führte im Allgemeinen zu einem weniger konfrontative Umgang mit Fan-Fiction- und RPG-Autoren.

Trotzdem befassen sich auch aufgeschlossene Schriftsteller meistens nicht direkt mit den Texten ihrer Fans, zum einen weil sie mögliche Rechtsstreitigkeiten von vorneherein vermeiden wollen, aber auch, um nicht in einen Interessenskonflikt zu geraten. Im Regelfall bleiben Fan Fictions daher bewusst unbeachtet. Die meisten erfolgreichen Autoren sind sich allerdings ihrer schreibenden Fans bewusst.

Fortschreitende Professionalisierung

Inzwischen ist aber nicht nur die Außenwahrnehmung von Fan Fictions eine andere, auch die Fan-Fiction-Kultur hat sich stetig verändert und weiterentwickelt. Durch neue Plattformen, wie Wattpad, aber auch ein gewandeltes Selbstverständnis der Autoren befindet sich die Community in einem Prozess der Professionalisierung.

Hinter großen Online-Archiven und Plattformen aber auch kleineren RPG-Foren stehen Administratoren- und Support-Teams, die sich um den technischen Unterbau kümmern. Moderatoren betreuen die Community, kontrollieren den Einhalt der Regeln und schlichten Streitigkeiten. Archive of Our Own bietet seinen Mitgliedern im Einzelfall sogar Unterstützung bei Rechtsstreitigkeiten.

»We are committed to defending fanworks against legal challenges. Our position on transformative fanworks is detailed in the OTW FAQ. We have legal resources and alliances on which we can draw. However, that is not a guarantee that the organization can or will fight each battle. The Board will take into account a variety of factors, both legal and otherwise, in responding to a legal challenge.«

AO3 – Terms of Service – What we believe

"Spend" by 401(K) 2013
“Spend” by 401(K) 2013. Licensed with CC BY-SA 2.0.

Diese Arbeit wird entweder durch Spenden finanziert (z. B. bei AO3) oder durch Werbeeinnahmen (z. B. bei Wattpad). Generell ausgeschlossen ist jedoch weiterhin, dass die Autoren mit ihren Geschichten Geld verdienen. An diesem Grundsatz, der aufgrund der urheberrechtlichen Bestimmung eigentlich nicht verhandelbar ist, wird derzeit jedoch gerüttelt. Auf Patreon suchen inzwischen auch vermehrt Fan-Fiction-Autoren nach monetärer Unterstützung, was in der Community recht kritisch gesehen wird, weil befürchtet wird, dass, sollten immer mehr Autoren diesem Beispiel folgen, die Duldung von Fan Fiction durch die Rechteinhaber auf’s Spiel gesetzt wird.

Für die großen Plattformen ist dies ebenfalls ein Problem. Bei AO3 ist die Verbreitung von kommerziellen Produkten und Aktivitäten bspw. generell untersagt. Bereits die Verlinkung auf Patreon ist in diesem Kontext hochproblematisch, weshalb es immer wieder zur Sperrung von Accounts kommt. Letztlich können aber auch die Plattformbetreiber die Nutzung von Patreon nicht unterbinden.

Im Bereich der RPGs ist diese Entwicklung eher irrelevant, da an den kollaborativ erzählten Geschichten kein einzelner Autor die Rechte daran für sich allein beanspruchen und auf diesem Wege monetarisieren könnte.

Ob die Nutzung von Patreon und ähnlicher Angebote daher zu einem Problem für die Fan-Fiction-Kultur an sich wird, ist zumindest im Moment noch nicht klar. Zweifelsohne wird diese Entwicklung aber zu neuerlichen Debatten über die derzeit geltenden rechtlichen Bestimmungen führen und gegebenenfalls sogar eine juristische Nachjustierung erzwingen.

Die Urheberrechtsreform ist zwar erst vor 2 Jahren beschlossen worden und wird erst in diesem Jahr in nationales Recht umgesetzt, das bedeutet aber noch lange nicht, dass sie auch auf der Höhe der Zeit ist.


QUELLEN
[1] Ullstein Buchverlage: I love writing: Plagiat oder Inspiration? Ausleuchtung einer Grauzone

[2] Jennifer Keishin Armstrong: How Sherlock Holmes changed the world (2016)

[3] Reißmann, Wolfgang; Klaas, Nadine; Hoffmann Dagmar: Fan Fiction, Urheberrecht und Empirical Legal Studies. IN: POP. Kultur und Kritik, Heft 10, S. 158 (2017)

[4] Maria Jose and John Tenuto: Spockanalia — The first Star Trek Fanzine (2014)

[5] Reißmann, Hoffmann: Selbstbestimmungen in Fan Fiction Kulturen. In: M&K, Jahrgang 66, Heft 4, S. 469 (2018)

[6] Summerer, Claudia: “Illegale Fans”, S. 48-49 (2015)

[7] Reißmann, Wolfgang; Klaas, Nadine; Hoffmann Dagmar: Fan Fiction, Urheberrecht und Empirical Legal Studies. IN: POP. Kultur und Kritik, Heft 10, S. 162 (2017)

[8] Djordjevic, Valerie: Mashups, Remixes, Samples. In: Dossier Urheberrecht, S. 103 (2018)

[9] Reißmann, Wolfgang; Hoffmann, Dagmar: Selbstbestimmungen in Fan Fiction Kulturen. In: M&K, Jahrgang 66, Heft 4, S. 470 (2018)

Beitragsbild

“Urheberrecht” by Skley. Licensed with CC BY-ND 2.0.


Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Content Management (Wintersemester 2020/21, Prof. Dr.-Ing. Steinberg) entstanden. Die besten Beiträge stellen wir Euch hier in den nächsten Wochen nach und nach vor.

Crypto War 3.0 – Ist das nicht nur was für Nerds?

Beitragsbild

Autor: Leopold Paris


Das Thema im Rat der Europäischen Union Ende 2020 war “Verschlüsselung von online Kommunikation”. Der Rat der EU diskutiert, wie z. B. E-Mails, WhatsApp Nachrichten oder Snaps von einem internetfähigen Gerät zum anderen gelangen. Eine Geschichte über die Crypto Wars.

“Da gibts doch nichts großes zu diskutieren”, würde jetzt manch einer sagen.
“Ja, irgendwie werden diese Bilder und Texte in Einsen und Nullen umgewandelt und dann äähm… einfach zum Empfänger geschickt”. Meist schließt die Person den Satz mit einem selbstsicheren Gesichtsausdruck. Dieser Gesichtsausdruck geht dann zu einem Altklugen über, sobald die Leute drum herum murmelnd ihre Zustimmung bekunden.

Bei dieser schwammigen Aussage wurde auch nichts Falsches behauptet. Nur ein falsches Bild von online Kommunikation und deren Komplexität wird vermittelt.

Inhalt

  1. Online Kommunikation
    1. Kryptographie
    2. Von da Vinci zurück zur Cäsar Chiffre
    3. Entschlüsseln – vom Geheimtext zurück zum Klartext
  2. Entschließung vom Rat der EU
    1. Crypto Wars
    2. Die Lösung: Backdoor?
    3. Juniper-Skandal
    4. Backdoors in Europa
  3. Crypto War 4.0, 5.0, …?
  4. Quellen

Online Kommunikation

Das falsche Bild ensteht bei den Worten “einfach zum Empfänger geschickt”. Darunter kann man sich vorstellen, dass Nachrichten auf einer direkten Linie zwischen den zwei Smartphones gesendet werden. So ist es dann auch selbstverständlich, dass der Rest der Welt nichts von der Kommunikation mitbekommt.

Grafik 2
Eine Karte von den Unterwasser Internet-Infrastruktur 
 

Dieses Bild ist aber komplett irreführend. Die Nachricht, die dann auf dem Gerät des Empfängers aufploppt, ist nur die Ziellinie einer langen Strecke die in Sekunden zurück gelegt wird.


Wenn wir Alice zum Beispiel eine WhatsApp Nachricht an Bob verschicken lassen, könnte es sein, dass die Nachricht zu einem Server in Grönland oder in den USA weitergeleitet wird. Und das alles in Sekunden. Auf all den Zwichenstationen, die auf dem Weg liegen (z.B. Routern und Switches) kann die Nachricht abgegriffen werden. (vgl. Snowden 2019)

Kommunikation zwischen zwei Mobiltelefonen. Darstellung: WhatsApp
Eine Modell einer online Kommunikation am Beispiel WhatsApp.


Das ist dann so als ob der private WhatsApp Chat von Alice und Bob noch einen weiteres Mitglied hätte namens Eve. Und dabei wissen Alice und Bob nichts von Eve.
Gegen das Abgreifen von Daten kann man sich bei so einem komplexen Sytem nur schwer wehren. Aber man kann dafür sorgen, dass die Informationen in den falschen Händen wie Kauderwelsch aussehen. Mithilfe von Verschlüsselung.

Kryptographie

Um unrechtmäßigen Zugriff auf private Kommunikation zu verhindern, gibt es Kryptographie. Kryptographie kommt aus dem Altgriechischen und bedeutet so viel wie “Geheimschrift” bzw. “Verschlüsselung”. Obwohl sie in der modernen IT-Welt nicht mehr weg zu denken ist, sind Geheimschriften nichts Neues. Selbst Leonardo da Vinci dokumentierte mithilfe einer Geheimschrift (Spiegelschrift) seine Forschungen.
(vgl. Wikipedia 2020)

Eine Seite aus den Dokumentationen von Leonardo in Spiegelschrift
Eine Doppelseite aus Leonardo da Vinci’s Büchern. Geschrieben in Spiegelschrift (vgl. Wikipedia 2020)

Von da Vinci zurück zur Cäsar Chiffre 

Nach dem römischen Schriftsteller Sueton nutzte der Feldherr Gaius Julius Cäser eine Geheimschrift für militärische Korrespondenzen. Diese Geheimschrift ist heute als Cäsar Chiffre bekannt. Aus dem Namen “Gaius” wird dann “Hbjvt”. Der Algorithmus dahinter ist einfach, wenn man ihn kennt. Jeder Buchstabe wird um eine Stelle verschoben. Aus “a” wird “b” aus “b” wird “c”, … aus “z” wird wieder “a”. Somit konnte kein Aussenstehender, der den Brief abfing, etwas damit anfangen. (vgl. Wikipedia 2021)
Mit der Außnahme, er kennt den Algorythmus und den Schlüssel.
Der Algorythmus ist bei der Cäsar Chiffre die Verschiebung von den Buchstaben. Und der Schlüssel ist im obigen Beispiel, mit dem Namen “Gaius” -> 1.

#https://gist.github.com/nchitalov/2f2b03e5cf1e19da1525
 def caesar_encrypt(klartext, schluessel):
     outText = []
     cryptText = []
     lowercase = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
     #Durch jeden Buchstaben durchlooben und um n Schritte Verschieben
     for eachLetter in klartext:
       index = lowercase.index(eachLetter)
       crypting = (index + schluessel) % 26
       cryptText.append(crypting)
       newLetter = lowercase[crypting]
       outText.append(newLetter)
     return outText
 
  #Vordefinierte Funktion ausführen
  #Mit dem Klartext 'Gaius' und dem Schlüssel 2
  geheimtext = caesar_encrypt('Gaius', 2)
  #Ergebnis der Funktion ausgeben
  print(geheimtext)


Vielleicht erscheint einem der Algorythmus anspruchsvoller als der Schlüssel. Der Schlüssel ist aber viel wichtiger und entscheidet darüber, wie sicher eine Verschlüsselung ist.

Entschlüsseln – vom Geheimtext zurück zum Klartext

Bei der Cäsar Chiffre werden die Buchstaben um je x Stellen verschoben. Das deutsche Alphabet besteht ohne Umlaute und Sonderzeichen (z. B. ß) aus 26 Buchstaben. So kann der Schlüssel 26 verschiedene Werte annehmen. All diese 26 Möglichkeiten kann ein Computer in Sekunden ausprobieren. Und so die Verschlüsselung in Sekunden knacken. Das nennt man dann “Brute Force”. (vgl. heise online 2021)

Wenn wir einen “Brute Force” bei aktuellen Verschlüsselungs-Algorythmen anwenden, z.B. RSA mit einem 512-Bit Schlüssel, dann müsste der Computer dann 2512 Möglichkeiten durchprobieren.

Schon bei einer 256-bit Verschlüsselung gibt es
115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,935
bzw. 2256 mögliche Schlüssel

Wenn wir davon ausgehen, dass jedes Atom im Universum ein Computer ist und jeder in einer Millisekunde einen möglichen Schlüssel ausprobiert, dann benötigt man mit der “Brute Force” Methode mehr als 10211 Jahre. Das ensptricht ein vielfaches der Lebenszeit des Universums (13,75*109 Jahre).
(vgl. Stack Exchange Inc. 2015)

Das Entschlüsseln entwickelt sich aber auch stetig weiter. Das kryptographische Verfahren RSA verwendet teilweise noch 1024-bit Schlüssellängen. Aber solche Schlüssel sind mittlerweile mit spezieller Software zu knacken. Dafür benutzt die Software statistische Verfahren und muss nicht wie beim “Brute Force” 21024 Möglichkeiten ausprobieren. Deswegen gelten momentan 2048-Bit Schlüssel und 4096-Bit Schlüssel als sicher. Diese Schlüssel werden zum Beispiel bei vielen Webseiten, die https (Hyper Text Transfer Protocol Secure) benutzen, verwendet. (vgl. PC-Welt 2014)

Das sind die Basics zum Thema Verschlüsselung. Bei modernen Verschlüsselungverfahren werden weitere Hürden aufgestellt um das Entschlüsseln zu erschweren.

Weiterführende Links

Entschließung vom Rat der EU

Eine Entschließung vom Rat der EU ist eine Art Stellungnahme von den aktuellen Regierungen der EU-Mitgliedsstaaten. Der Titel des vierseitigen Dokuments lautet “Sicherheit durch Verschlüsselung und Sicherheit trotz Verschlüsselung”. Diese Gegensätzlichkeit im Titel zieht sich mehr oder weniger im ganzen Dokument durch. In sieben Kapiteln fordert der Rat der EU einen “Regelungsrahmen zu entwickeln”. Der einerseits den Behörden ermöglichen soll “ihre operativen Aufgaben wirksam zu erfüllen und andererseits die Privatsphäre, die Grundrechte und die Sicherheit der Kommunikation zu schützen”. Der Rat pocht auf Innovation mithilfe der Technologiebranche, Forschung und Wissenschaft. (vgl. Rat der EU 2020)

Crypto Wars

Diese Debatte zieht sich jetzt schon seit Jahren hin. Crypto War 1.0, Crypto War 2.0 u.s.w. Der sogenannte “Crypto War” begann in den 1990er-Jahren. In dieser Zeit wurde nach Möglichkeiten gesucht, den Zugang zu verschlüsselter Kommunikation für Strafverfolgungsbehörden zu vereinfachen. (vgl. heise Online 2020a)

Logo der National Security Agency (NSA). Dem US-Amerikanischen Geheimdienst. Vergleichbar mit dem brittischen GCHQ oder dem deutschen BND

 

Begonnen hat der “War” in den USA. Dort wurde dem Senat ein Gesetzesentwurf vorgelegt, um den Strafverfolgungsbehörden Zugriff auf die verschlüsselte Kommuikation von Nutzern zu verschaffen. Zusätzlich machte die NSA (National Security Agency) den Vorschlag, dass alle Hersteller von Telefonanlagen den von der NSA selbst entwickelten Clipper Chip zur Verschlüsselung einsetzen müssen. (vgl. Tresorit Team 2016)


Bei diesem Chip handelt es sich um ein im Jahre 1993 entwickeltes symmetrisches Verschlüsselungssystem. Der sogenannte Escrowed Encryption Standard (EES) ermöglicht den Zugriff auf verschlüsselte Kommunikation mithilfe von zwei Schlüsseln. Einer ist bei den Behörden hinterlegt. Und der Andere wird nur auf richterliche Anordnung freigegeben. Nach nur drei Jahren wurde das Projekt aufgrund von zahlreichen Protesten eingestellt.
(vgl. Tresorit Team 2016)

Die Lösung: Backdoor?

Als Backdoor wird eine absichtlich eingebaute Verschlüsselungs-Hintertür bezeichnet. Praktisch wäre es dann ein Schlüssel, mit dem man eine bestimmte Verschlüsselung immer knacken kann. Momentan sind diese Backdoors eine Möglichkeit das Ziel “Sicherheit durch Verschlüsselung und Sicherheit trotz Verschlüsselung” zu erreichen. Diese Methode sorgt aber für heftige Kritik. Die Bitkom, der Digitalverband Deutschlands, kritisiert die Hintertüren. Backdoors seien nicht dauerhaft kontrollierbar und eine Einladung für Kriminelle und ausländische Nachrichtendienste. (vgl. bitkom 2020)

Juniper-Skandal

Juniper bietet Internetinfrastruktur für Unternehmen an. Von Produkten wie WiFi-Router bis hin zu Cloud Diensten. (vgl. Juniper Networks Inc. 2021)
Ende 2015 began der Skandal rund um den US-Konzern Juniper. Der Netzausrüster hatte auf Verlangen der NSA eine Hintertür in seinem Betriebssystem ScreenOS eingebaut. Ende Oktober 2020 gab Juniper dann gegenüber dem US-Kongress zu, dass die Hintertür von einem anderen Staat übernommen wurde und so die NSA ausperrte. Ermittler gehen davon aus, dass es sich um China handelt.
Das ist ein perfektes Beispiel dafür, wie Hintertüren nach hinten los gehen können. 😀
(vgl. heise Online 2020b)

Backdoors in Europa

Am 11. Januar 2021 antwortete die EU-Innenkommissarin Ylvy Johansson auf einen Brief von drei liberalen EU-Abgeordneten. Thema des Briefes waren Backdoors. In der Antwort der EU-Innenkommissarin schließt sie Hintertüren, um Zugriff auf verschlüsselte Daten zu erlangen, aus. (vgl. STANDARD Verlagsgesellschaft m.b.H. 2021)

Sinnbildliche Darstellung einer Backdoor, dessen Zugang geheim ist.
Sinnbildliche Darstellung einer Backdoor, dessen Zugang geheim ist.

Crypto War 4.0, 5.0, …?

Bis jetzt existieren noch keine ausgeglichenen Technologien, um online Kommunikation für Dritte zu verschlüsseln, aber für Strafverfolgungsbehörden doch wieder zu entschlüsseln. Bei diesem Diskurs, der nun schon über 20 Jahre andauert, werden nur langsam Meilensteine erreicht.

Schloss mit dazugehörigem Schlüssel

Die EU-Mitgliedsstaaten haben sich dafür entschieden, dass Verschlüsselung wieder mehr Aufmerksamkeit gewidmet werden soll. Der richtige Weg dafür soll Innovation sein. Eine Innovation, die auf dem Wissen und den Interessen von Wirtschaft, Wissenschaft und Politik entsteht.

Am Ende betrifft eine solche Innovation aber jeden Einzelnen und jede WhatsApp Nachricht eines jeden Einzelnen. Und auch wenn es “Nerds” sind, die diese Algorythmen entwickeln, sollte jedem bewusst sein wie privat seine online Kommunikation sein soll und ist.

Weiterführende Links

Quellen

Wikipedia (2020) a: Siegelschrift. Geschichte. Zuletzt aktualisiert am 05.05.2020. Online unter https://de.wikipedia.org/wiki/Spiegelschrift [Abruf am 29.01.2021]

Snowden, Edward (2019): Permanent Record. Meine Geschichte. Frankfurt a.M.: Fischer. ISBN 978-3-10-397482-9

Wikipedia (2021): Caesar-Verschlüsselung. Geschichte. Zuletzt aktualisiert am 21.01.2021. Online unter https://de.wikipedia.org/wiki/Caesar-Verschl%C3%BCsselung#Geschichte [Abruf am 27.01.2021]

Stack Exchange Inc. (2015): How much computing resource is required to brute-force RSA?. Online unter https://crypto.stackexchange.com/questions/3043/how-much-computing-resource-is-required-to-brute-force-rsa [Abruf am 29.01.2021]

heise Online (2021): heise Developer. Was man über Kryptografie wissen sollte. Zuletzt aktualisiert am 11.01.2021. Online unter https://www.heise.de/developer/artikel/Was-man-ueber-Kryptografie-wissen-sollte-5001908.html [Abruf am 12.01.2021]

PC-Welt (2014): Verschlüsselung – Was ist noch unknackbar?. RSA. Zuletzt aktualisiert am 06.08.2014. Online unter https://www.pcwelt.de/ratgeber/Verschluesselung_-Was_ist_noch_unknackbar-Sicherheits-Check-8845011.html [Abruf am 30.01.2021]

Rat der EU (2020): Entschließung des Rates zur Verschlüsselung. Sicherheit durch Verschlüsselung und Sicherheit trotz Verschlüsselung. Abruf unter https://data.consilium.europa.eu/doc/document/ST-13084-2020-REV-1/de/pdf [Abruf am 25.01.2021]

heise Online (2020a): Mssing Link: Crypto Wars – der endlose Streit über sichere Verschlüsselung. Zuletzt aktualisiert am 22.11.2020 Online unter https://www.heise.de/hintergrund/Missing-Link-Crypto-Wars-der-endlose-Streit-ueber-sichere-Verschluesselung-4967574.html [Abruf am 22.01.2021]

Tresorit Team (2016): Crypto Wars: Seit 40 Jahren das alte Lied. Zuletzt aktualisiert am 30.11.2016. Online unter https://tresorit.com/blog/de/40-jahre-crypto-wars/ [Abruf am 25.01.2021]

bitcom (2020): Bitkom kritisiert geplante Hintertüren in Kommunikationsdiensten. Zuletzt aktualisiert am 10.11.2020. Online unter https://www.bitkom.org/Presse/Presseinformation/Bitkom-kritisiert-geplante-Hintertueren-in-Kommunikationsdiensten [Abruf am 29.01.2021]

Juniper Networks Inc. (2021): Produkte Lösungen und Service. Online unter https://www.juniper.net/de/de/products-services/ [Abruf am 31.01.2021]

heise Online (2020b): Juniper-Skandal: China übernahm angeblich Hintertür in Netzhardware. Zuletzt aktualisiert am 29.10.2020. Online unter https://www.heise.de/news/Juniper-Skandal-China-uebernahm-angeblich-Hintertuer-4942914.html [Abruf am 30.01.2021]

STANDARD Verlagsgesellschaft m.b.H. (2021): EU-Kommission stellt sich gegen Hintertüren in Verschlüsselung. Zuletzt aktualisert am 15.01.2021. Online unter https://www.derstandard.de/story/2000123317855/eu-kommission-stellt-sich-gegen-hintertueren-in-verschluesselung?ref=rec [Abruf am 30.01.2021]


Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Content Management (Wintersemester 2020/21, Prof. Dr.-Ing. Steinberg) entstanden. Die besten Beiträge stellen wir Euch hier in den nächsten Wochen nach und nach vor.

Was ist Flask?

Was ist Flask?

Autor: Esben Christian Pedersen


Inhalt

Was ist Flask überhaupt?

Flask ist ein WSGI Micro-Framework für Webapplikationen. Ursprünglich wurde Flask als Aprilscherz von Armin Ronacher im Jahr 2010 entwickelt. Auf Grund steigender Beliebtheit unter den Usern, gründete Armin Ronacher die „The Pallets Project“-Sammlung von Open Source Code Bibliotheken. Diese Sammlung dient nun als Organisation hinter Flask und weiteren Bibliotheken wie Werkzeug und Jinja, um die Flask aufgebaut ist. Dabei stützt sich Flask nur auf die nötigsten Komponenten die für die Webentwicklung benötigt werden ( routing, request handling, session). Alle anderen Komponenten müssen dementsprechende entweder selbst entwickelt oder über zusätzliche Pakete hinzugefügt werden.[1]

Was Flask so außergewöhnlich macht ist der simple Einstieg und die Effizienz im Zusammenspiel mit anderen Python Bibliotheken. Was dem Entwickler erlaubt Web-Applikationen mit Flask im größeren Stil zu entwickeln und auszubauen, ohne dem Entwickler etwas aufzuzwingen. Da die „The Pallets Project“-Sammlung sich einer großen Unterstützer Community erfreut, gibt es viele Erweiterungsmöglichkeiten welche die Funktionalität erhöhen und Flask äußerst flexibel werden lässt.[2]

Wie das Micro-Framwork Flask funktioniert soll in den folgenden Teilen dieses Beitrags deutlich werden. Sei es die simple installation, oder die einfach Handhabung.


Installation

Wie einfach es ist mit Flask eine Web-Applikation mit Flask zu erstellen soll in den folgenden Abschnitten deutlich werden.

Des Weiteren bietet es sich an beim Entwickeln einer Flask Web-Applikation eine virtuelle Entwicklungsumgebung wie Pythons hauseigene virtualenv zu verwenden um Projektabhängigkeiten und Bibliotheken für jedes Projekt entsprechend zu verwalten. Außerdem ermöglicht die virtualenv eine schnelle und einfach Portierung bzw. ein schnelles unkompliziertes Deployment einer Applikation.

Wie Pythons virtuelle Entwicklungsumgebung funktioniert ist hier näher beschrieben „virtualenv“.

Um Flask zu installieren kann man einfach “pip” benutzen. Dies ist der Package Installer für Python:

$ pip install Flask

So einfach lässt sich Flask installieren mit seinen benötigten Paketen installieren.[3]

Hello World!

Wie einfach das erstellen einer Web Applikation mit Python und Flask ist soll an einem simplen “Hello World” Beispiel verdeutlicht werden. Dazu wird die Datei “app.py” angelegt. Diese lässt sich einfach mit einem Texteditor öffnen und bearbeiten (z.B. PyCharm oder VS Code).

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello World!"

if __name__ == '__main___':
    app.run()

Zur Erklärung: In Zeile 1 importieren wir Flask und in initieren in Zeile 3 eine neue Instanz der Flask-Klasse und weisen sie der Variable “app” zu. In Zeile 5 wird ein “Decorator” benutzt um die Route/View “/” der View-Funktion “index()” zuzuweisen. Also einfach gesagt: Wird die Seite “/” des Servers im Browser angefragt, so führt dieser die View-Funktion aus die den Content “Hello World!” bereitstellt.[4]

Der letzt Abschnitt des Codes startet den Server sobald die Datei für den Interpreter aufgerufen wird. Wenn alles richtig installiert ist sollte nun folgender output zu sehen sein:

(webapp) $ py app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Die im Code erstellte Seite “/” mit der “index()”-Funktion lässt sich einfach über den Webbrowser öffnen. Dazu lediglich in der Adresszeile des Browser auf “http://localhost:5000/” oder “http://127.0.0.1:5000/” aufrufen. Die aufgerufene Seite sollte nun “Hello World!” in der linken oberen Ecke zeigen.

Routing and Views

Routing bezeichnet das auflösen und händeln von URLs. Dabei soll beim aufrufen einer URL der korrekte Inhalt im Browser dargestellt werden. Bei Flask wird dies mit dem Route- “Decorator” eine Funktion an eine URL gebunden um ihren Content nach dem Aufrufen der URL bereitzustellen. Das folgende Bild soll den Ablauf der URL Auflösung und dem damit verbunden bereitstellen von Content verdeutlichen.[5]

Im vorangegangenen Hello World Beispiel wird dies in Zeile 5 und 6 gemacht. Nach dem aufrufen der URL “http://localhost:5000/” sollte in der Konsole/der Shell folgendes zu sehen sein:

(webapp) $ py app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [29/Jan/2021 11:56:33] "GET / HTTP/1.1" 200 –

Es ist zu sehen das der Browser eine Anfrage für die „/“-Route an den Server stellt. Dieser verarbeitet die Anfrage entsprechend der mit der Route verbundenen View-Funktion “index()”. Im Anschluss sendet der Server http-status: 200 (OK) und rendert „Hello World!“.

In der Konsole stehen sämtliche Anfragen und http-status codes die vom Flask-Server verarbeitet werden.

Routen und http-Methoden:

Der „Decorator“ kann ein weiteres Argument annehmen. Dieses Argument ist eine Liste mit den für den „Decorator“ erlaubten http-Methoden.

from flask import Flask

app = Flask(__name__)

@app.route(„/users/“, methods=['GET', 'POST'])
def users():
    # Routr Logic #

Somit lassen sich Routen in der Nutzung bestimmter http-Methoden einschränken. Ist jedoch keine Liste angegeben so ist die “GET”-Methode als Standard festgelegt.

Mithilfe der “Decorator” lassen sich auch dynamische und variable Regeln für Routen festlegen, da statische Routen eine Website stark einschränken können. So lässt sich im folgenden Beispiel eine Profilseite für registrierte User anlegen oder gepostete Artikel/Beiträge bekommen eine eigene URL basierend auf dem Datum an dem sie Online gestellt worden und ihrem Titel.

Dabei geben die „<>“ an ob es sich um eine Variable handelt. So lassen sich Routen dynamisch generieren. Zusätzlich lässt sich der Variablen-Typ angeben der verarbeitet werden soll „<datatype:variablename>“. Folgende Variablentypen sind für Routen vorgesehen und möglich:

  • string: Akzeptiert Text ohne „/“.
  • int: Akzeptiert ganze Zahlen (integers).
  • float: akzeptiert numerische Werte die einen Dezimalpunkt enthalten.
  • path: Akzeptiert Text mit „/“ (Pfadangaben)

Dynamische Routen können dementsprechend im Gegensatz zu statischen Routen Parameter entgegennehmen und verarbeiten. Somit ließe sich auch eine API mit Flask umsetzen um Daten für User zugänglicher und nutzbarer zu machen oder einen erhöhten Automatisierungsgrad für Datenabfragen zu ermöglichen. Um dies deutlich zu machen dienen die folgenden Beispiele:[6]

from flask import Flask, escape

app = Flask(__name__)

@app.route(„/users/<username>“)
def profile(username):
    return f'<h1>Welcome { escape(username) }</h1>'
Return “randomuser” nach Browseranfrage
from flask import Flask, escape

app = Flask(__name__)

@app.route(„/article/<int:year>/<int:month>/<title>“)
def article(year, month, title):
    month_dict = {
        "1": "January",
        "2": "February",
        "3": "March",
        "4": "April",
        "5": "May",
        "6": "June",
        "7": "July",
        "8": "August",
        "9": "September",
        "10": "October",
        "11": "November",
        "12": "December"
        }
    return f'<h1>"{ escape(title) }" from { escape(month_dict[str(month)]) } { escape(year) }</h1>'
Return Date and Title nach Browseranfrage

So einfach diese Beispiele sind, so geben sie doch einen deutlichen Ausblick auf die Möglichkeiten, welche sich mit Flask bieten. Welche Unternehmen Flask in ihrer Entwicklung benutzen kann hier eingesehen werden.

Die Template Engine

Wie werden jetzt aus statischen HTML-Dateien dynamische Websiten mit Flask? Ganz einfach, mit Hilfe der eingebauten Template Engine Jinja. Jinja ist eine vielseitige und einfache Templete Engine mit der sich unter anderem auch dynamische HTML-Inhalte erstellen lassen. Sie basiert dabei auf der “Django” Template Engine bietet jedoch viel mehr Möglichkeiten wie volle “unicode” Unterstützung und “automatic escaping” für mehr Sicherheit in Webanwendungen. Zusätzlich lassen sich die gängisten verwendeten Codeblöcke der html-templates immer wieder verwenden und vielseitig einsetzen. Dabei verwendet die Template Engine Variablen, Ablauflogiken und Anweisungen um im Template verwendete Ausdrücke mit Inhalt zu füllen.[7]

Funktionsweise Template Engine Jinja

Um das ganze noch mehr zu veranschaulichen dient der folgende Beispiel Code mit der angegeben Projektstruktur:

|-- app.py
|-- static
|   `-- css
|       `-- main.css
-- templates
    |-- about.html
    |-- index.html
    |-- layout.html
    `-- page1.html
<!DOCTYPE html>
<html lang="en">

  <head>
    <!-- meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Title: -->
    <title>Flask App</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
  </head>
    <!-- Start of body -->
  <body>
    <header>
      <h1>Flask Web App</h1>
    </header>
    <div class="navbar">
      <strong><ul class="navmenu">
        <li><a href="{{ url_for('home') }}">Home</a></li>
        <li><a href="{{ url_for('page1') }}">Page 1</a></li>
        <li><a href="{{ url_for('about') }}">About</a></li>
      </ul></strong>
    </div>
    <content>
      <div class="container">
        <!-- At this place the child templates get rendered by Flask -->
        {% block content %}
        {% endblock %}
      </div>
    </content>
  </body>
</html>
{% extends "layout.html" %}

{% block content %}
<br>
<br>
<h1> Welcome to the Flask Web App</h1>
<br>
<br>
{% endblock %}
{% extends "layout.html" %}

{% block content %}
<br>
<br>
<h1> Page 1 example</h1>
<br>
<br>
{% endblock %}
{% extends "layout.html" %}

{% block content %}
<br>
<h2> About this Web App:</h2>
<br>
<h3> This App was build using Flask</h3>
{% endblock %}
/* main.css file containing the styling information for the flask webapp */

body {
    margin: 10;
    padding: 5;
    font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
    color: #444;
}

/* Header */

header {
    background-color: lightblue;
    height: 40px;
    width: 100%;
    opacity: .9;
    margin-bottom: 10px;
}

header h1 {
    margin: 0;
    font-size: 1.7em;
    color: black;
    text-transform: uppercase;
    float: left;
}

/* Body content */

.container {
    width: 100%;
    margin: 15;
}

/* navbar */

.navbar {
    margin: 5px;
    padding: 5px;
    border: 5px;

}

.navmenu {
    float: left;
    margin-top: 8px;
    margin-bottom: 8px;
    padding: 5px;
}

.navmenu li {
    display: inline;
}



.navmenu li a {
    color:slategray;
    text-decoration: none;
}
from flask import Flask, escape, render_template

app = Flask(__name__)

# Routes and Views:

@app.route("/")
def home():
    return render_template('index.html')

@app.route("/about/")
def about():
    return render_template('about.html')

@app.route("/page1/")
def page1():
    return render_template('page1.html')

# run flask server:
if __name__ == '__main__':
    app.run()

Wird der Server nun gestartet und im Browser die einzelnen Seiten der Applikation aufgerufen werden die html-templates für die entsprechende Seite gerendert.

Die Möglichkeiten zum nutzen von Templates sind schier endlos für Flask und bieten viel Raum für eigene Ideen und Umsetzungsmöglichkeiten in der Webentwicklung.

Fazit

Flask ist eine tolle Möglichkeit zum Einstieg in die Webentwicklung und bietet vielseitige Umsetzungsmöglichkeiten für Applikation, Websites oder APIs. Zudem ist es einfach zu lernen. Die dahinter stehende Community, die Umfangreiche Dokumentation, die Möglichkeit jedes Python Package miteinzubeziehen und die Masse an Tutorials bieten viel Raum um sich, Flask und die eigene App zu entwickeln/weiterzuentwickeln. Ohne das Flask dabei den Entwickelnden Rahmenbedingungen aufzwingt. Zusätzlich ist Lernkurve recht klein und der Entwickler wächst schnell in die Anforderungen und Möglichkeiten hinein.

  1. Stender, Daniel (2017): Tropfen um Tropfen. In: Entwickler Magazin, Jg. 2017, H. 6. Online unter: https://kiosk.entwickler.de/entwickler-magazin/entwickler-magazin-6-2017/tropfen-um-tropfen/ [Abruf am 10.01.2021]
  2. Stender, Daniel (2017): Tropfen um Tropfen. In: Entwickler Magazin, Jg. 2017, H. 6. Online unter: https://kiosk.entwickler.de/entwickler-magazin/entwickler-magazin-6-2017/tropfen-um-tropfen/ [Abruf am 10.01.2021]
  3. The Pallets Project (2020): Installation. Online unter https://flask.palletsprojects.com/en/1.1.x/installation/ [Abruf am 04.01.2021]
  4. The Pallets Project (2020): A minimal application. Online unter https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application [Abruf am 04.01.2021]
  5. The Pallets Project (2020): Routing. Online unter https://flask.palletsprojects.com/en/1.1.x/quickstart/#routing [Abruf am 04.01.2021]
  6. The Pallets Project (2020): Variable Rules. Online unter: https://flask.palletsprojects.com/en/1.1.x/quickstart/#variable-rules [Abruf am 04.01.2021]
  7. The Pallets Project (2020): Templating. Online unter: https://flask.palletsprojects.com/en/1.1.x/templating/ [Abruf am 04.01.2021]

Alle Codebeispiele sind selbst erarbeitet und getestet.


Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Content Management (Wintersemester 2020/21, Prof. Dr.-Ing. Steinberg) entstanden.

Die besten Beiträge stellen wir Euch hier in den nächsten Wochen nach und nach vor.

Forty in 49: Ein Spiel für Gedächtnis und räumliches Vorstellungsvermögen

Beitragsbild forty in 49 - ein Spiel für das Gedächtnis und das räumliche Vorstellungsvermögen

Autor: Jannis Fortmann

Link zum Spiel
Zip Datei zum Download

Inhalt

Konzept

Von Anfang an war es mein Plan, ein simples und optisch ansprechendes kleines Spiel zu designen, bei dem Animationen sinnvoll zum Einsatz kommen.

Nach ein paar verworfenen Ideen entschied ich mich für diese Variante, bei der die räumliche Wahrnehmung und das Gedächtnis des Spielers auf die Probe gestellt wird. Das Konzept des Spiels ist angelehnt an einen Intelligenztest für Schimpansen, bei dem deren Arbeitsgedächtnis getestet wird. Bei diesem werden aufeinanderfolgende Zahlen auf einem Bildschirm abgebildet, diese zahlen müssen dann in der richtigen Reihenfolge gedrückt werden. Nachdem die erste Zahl gedrückt wurde, werden alle anderen hinter identisch aussehenden Feldern versteckt.

Mein Spiel „forty in 49“ funktioniert nach einem ähnlichen Prinzip. Anstatt einer bestimmten Reihenfolge geht es hierbei aber um die Position der Felder. In einem Raster sind 7×7 Felder angeordnet,. Zu Beginn des Spiels verschwinden 40 der 49 Felder für wenige Sekunden. Der Spieler muss sich die Position der übrigen 9 Felder (Bomben) merken und diese vermeiden. Das Ziel ist es, möglichst viele der 40 Felder anzuklicken. Klickt man auf eine Bombe, ist das Spiel vorbei.

Animationen

Die Animationen erfüllen sowohl funktionale als visuelle Zwecke.

Um die Orientierung zu vereinfachen, werden Felder größer und ändern ihre Farbe, wenn der Mauszeiger darüber hovert. Wird ein Feld angeklickt, wird es entweder grün und verschwindet in einer rotierenden Animation, oder es wird rot und dreht sich langsam um 180° um die y-Achse und um 45° um die z-Achse. Dadurch wird dem Spieler visuell verdeutlicht, ob er richtig lag. Um das Ganze auditiv zu unterstützen, gibt es für den Klick auf die zwei Arten von Feldern jeweils einen Soundeffekt.

Ist das Spiel vorbei (alle richtigen Felder oder eine Bombe wurden geklickt), erscheint eine Karte mit der Punktzahl. Sie bewegt sich von unten nach oben und landet mittig über dem Spielfeld. Außerdem gibt es natürlich die fade-out/fade-in Animation am Anfang, ohne die das Spiel überhaupt nicht möglich wäre.

Technische Umsetzung

Die Seite wurde mithilfe von HTML, CSS und JavaScript erstellt.

HTML

In der HTML-Datei wird der Aufbau der Seite bestimmt. Alle nicht-dynamischen Inhalte werden definiert und mithilfe von DIV-Containern positioniert.

In dem DIV „wrap“ befinden sich alle anderen Objekte, es definiert den Abstand zu den Seitenrändern. Unter der Überschrift und einer kurzen Spielbeschreibung befindet sich der Start-Button und darunter der aktuelle Punktestand.

Das Spielfeld besteht aus 49 einzelnen DIVs für die kleinen, quadratischen Felder. Diese sind umschlossen von dem DIV „grid“, welches sich innerhalb des DIV „background“ befindet.

Darunter befinden sich die DIVs „gameOver“ und „finalScore“ sowie der Restart-Button. Diese Elemente bestimmen die Karte, die zum Ende des Spiels erscheint, bis dahin sind sie unsichtbar.

Jedem der 49 Spielfeld-DIVs werden drei Klassen zugeordnet. Alle bekommen die Klasse „cell“, über die alle Felder auf einmal angesprochen werden können. Außerdem bekommt jedes Feld eine individuelle Klasse (c1 bis c49) und entweder die Klasse „bomb“ oder „noBomb“. Damit können die beiden Arten von Feldern getrennt voneinander bearbeitet werden.

<!DOCTYPE html>
<html lang="en" >
  <head>
    <meta charset="UTF-8">
    <title>forty in 49</title>
    <link rel="stylesheet" href="./style.css">
  </head>
  <body>
    <div class="wrap">
      <h1>
        forty in 49
      </h1>
      <p>
        a simple game<br>
        49 tiles - 40 are good 9 are bad<br>
        press start to see the bad ones<br>
        click on all the good ones
      </p>
      <button id="start">
        start
      </button>
      <div id="score">
        score: 0
      </div>
      <div class="background">
      </div>
      <div class="gameOver">
        your final sccore is: 
        <div id="finalScore">
          0
        </div>
        <button id="restart">
          restart
        </button>
      </div>
    </div>
    <script  src="./script.js">
    </script>
  </body>
</html>
<div class="background">
   <div class="grid">
     <div class="cell c1 noBomb"></div>
     <div class="cell c2 bomb"></div>
     <div class="cell c3 noBomb"></div>
     <div class="cell c4 noBomb"></div>
     <div class="cell c5 noBomb"></div>
     <div class="cell c6 noBomb"></div>
     <div class="cell c7 noBomb"></div>
     <div class="cell c8 noBomb"></div>
     <div class="cell c9 noBomb"></div>
     <div class="cell c10 noBomb"></div>
     <div class="cell c11 bomb"></div>
     <div class="cell c12 noBomb"></div>
     <div class="cell c13 bomb"></div>
     <div class="cell c14 noBomb"></div>
     <div class="cell c15 noBomb"></div>
     <div class="cell c16 noBomb"></div>
     <div class="cell c17 noBomb"></div>
     <div class="cell c18 noBomb"></div>
     <div class="cell c19 noBomb"></div>
     <div class="cell c20 noBomb"></div>
     <div class="cell c21 noBomb"></div>
     <div class="cell c22 noBomb"></div>
     <div class="cell c23 noBomb"></div>
     <div class="cell c24 bomb"></div>
     <div class="cell c25 noBomb"></div>
     <div class="cell c26 bomb"></div>
     <div class="cell c27 noBomb"></div>
     <div class="cell c28 noBomb"></div>
     <div class="cell c29 bomb"></div>
     <div class="cell c30 noBomb"></div>
     <div class="cell c31 noBomb"></div>
     <div class="cell c32 noBomb"></div>
     <div class="cell c33 noBomb"></div>
     <div class="cell c34 bomb"></div>
     <div class="cell c35 noBomb"></div>
     <div class="cell c36 noBomb"></div>
     <div class="cell c37 bomb"></div>
     <div class="cell c38 noBomb"></div>
     <div class="cell c39 noBomb"></div>
     <div class="cell c40 noBomb"></div>
     <div class="cell c41 noBomb"></div>
     <div class="cell c42 noBomb"></div>
     <div class="cell c43 noBomb"></div>
     <div class="cell c44 noBomb"></div>
     <div class="cell c45 noBomb"></div>
     <div class="cell c46 bomb"></div>
     <div class="cell c47 noBomb"></div>
     <div class="cell c48 noBomb"></div>
     <div class="cell c49 noBomb"></div>
   </div>
 </div>

CSS

In CSS wird das optische Erscheinungsbild der Seite bestimmt.

Die Hintergrundfarbe und Stil der Schrift werden definiert.

body {
  background-color: #4d4d4d;
  color: #b488b8;
  font-family: Calibri;
  text-align: center;
  text-transform: uppercase;
}

h1 {
  font-size: 60px;
}

Die Buttons werden abgerundet und bekommen jeweils eine Hintergrundfarbe.

#start {
  color: #b488b8;
  background-color: #fff;
  font-family: Arial;
  font-size: 24px;
  text-transform: uppercase;
  border: none;
  border-radius: 5px;
  padding: 10px;
  margin: 20px;
}

#restart {
  display: none;
  color: #b488b8;
  background-color: #4d4d4d;
  font-family: Arial;
  font-size: 24px;
  text-transform: uppercase;
  border: none;
  border-radius: 5px;
  padding: 10px;
  margin: 20px;
}

Der Bereich unter dem Spielfeld wird abgerundet und bekommt eine andere Farbe.

.background {
  position: relative;
  box-sizing: border-box;
  float: left;
  background-color: #ababab;
  width: 100%;
  border-radius: 10px;
  padding-bottom: 5%;
  margin-top: 30px;
}

Die Spielfelder werden zu abgerundeten Quadraten und bekommen einen Rand und eine Farbe.

.cell {
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  float: left;
  width: 14.28%;
  padding-bottom: 13.8%;
  border: 1px solid white;
  background-color: #1e1e1e;
  border-radius: 5px;
}

Die Karte, die nach Beendung des Spiels erscheint, wird im gleichen Stil designt.

.gameOver {
  opacity: 0;
  box-sizing: border-box;
  float: left;
  background-color: #fff;
  width: 94%;
  padding: 5%;
  margin: 3%;
  border-radius: 10px;
  transition: transform 1s cubic-bezier(0.38, 0.4, 0, 1.18);
  transition-delay: 3s;
}

Auch die Animationen werden in CSS erzeugt.

Beim Klick auf den Start-Button werden alle Felder, die keine Bomben sind, für wenige Sekunden langsam durchsichtig und dann wieder sichtbar.

/* fade-out fade-in der nicht-Bomben beim Klick des Start-Buttons (keyframe fade) */
.noBomb.start {
  animation: fade 7s;
}
@keyframes fade {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

Beim hovern über einen der Buttons wird dieser um 10% größer.

#start:hover,
#restart:hover {
  transition: transform;
  transform: scale(1.1);
}

Die Farbe der der einzelnen Felder ändert sich beim hovern und sie wachsen langsam um 30%.

.cell:hover {
  transition: background-color, transform 0.5s;
  background-color: #b488b8;
  transform: scale(1.3);
}

Wird ein Feld angeklickt, das keine Bombe ist, wird es grün und in einer rotierenden Bewegung kleiner, bis es verschwunden ist.

/* Animation der nicht-Bomben nach Klick */
.noBomb.clicked {
  transition: background-color, transform 4s;
  background-color: #81c7a2 !important;
  transform: scale(0) rotate(720deg);
  pointer-events: none;   /* verhindert, dass ein Feld mehrfach geklickt werden kann */
}

Beim Klick auf eine Bombe wird diese rot und dreht sich um die y- und die z-Achse.

/* Animation der Bomben nach Klick */
.bomb.clicked {
  transition: background-color, transform 4s;
  background-color: #ff695e !important;
  transform: rotateY(180deg) rotateZ(45deg);
  pointer-events: none;
}

Nach Beendung des Spiels erscheint die Karte mit dem Punktestand, verliert langsam ihre Durchsichtbarkeit und wandert von unten nach oben, bis sie über der Mitte des Spielfelds landet.

JavaScript

JavaScript ist zuständig für die Funktionalität der Seite. Hier wird unter anderem definiert, was genau passiert, wenn ein bestimmtes Objekt angeklickt wird. Dabei wird dem Objekt eine neue Klasse zugeordnet, was die in CSS bestimmte Animation auslöst.

Beim Klick auf den Start-Button werden alle Objekte der Klasse „noBomb“ ausgewählt. Mithilfe einer For-Schleife wird ihnen die Klasse „start“ zugeordnet, was die in CSS definierte Animation auslöst.

// fade-out / fad-in bei Klick auf den Start-Button
let start = document.querySelector("#start");
let noBomb = document.querySelectorAll(".noBomb");
start.addEventListener("click", () => {
  for (var i = 0; i < noBomb.length; i++) {
    noBomb[i].classList.add("start");
  }
});

Ein Klick auf den Restart-Button sorgt dafür, dass die Seite neu geladen wird.

// neu laden der Seite bei Klick  auf Restart-Button
let restart = document.querySelector("#restart");
restart.addEventListener("click", () => {
  window.location.href = window.location.href;
});

Beim Klick auf eins der normalen Felder wird dem Objekt die Klasse „clicked“ zugeordnet und dadurch die CSS-Animation ausgelöst. Zusätzlich wird ein Soundeffekt abgespielt. Außerdem wird der Punktestand um 1 erhöht und überprüft, ob dadurch die maximale Punktzahl erreicht wurde. Falls dass der Fall ist, wird die Spielabschlusskarte gezeigt und animiert.

// Animation der nicht-Bomben und counter der Punktzahl
let c1 = document.querySelector(".c1");
c1.addEventListener("click", () => {
  c1.classList.add("clicked");
  count += 1;
  score.innerHTML = "score: " + count;
  finalScore.innerHTML = count;
  if (count == 40) {
    restart.classList.add("true");
    for (var i = 0; i < cell.length; i++) {
      cell[i].classList.add("over");
    }
    gameOver.classList.add("true");
  }
  audioNoBomb.play();
});

Der Klick auf eine der Bomben funktioniert ähnlich, auch hier wird die Animation ausgelöst. Außerdem wird allen Feldern die Klasse „over“ zugeordnet, was dafür sorgt, dass keine weiteren Felder angeklickt werden können.

// Animation der Bomben und der Karte nach Beendung des Spiels
let c2 = document.querySelector(".c2");
let cell = document.querySelectorAll(".cell");
c2.addEventListener("click", () => {
  finalScore.innerHTML = count;
  c2.classList.add("clicked");
  restart.classList.add("true");
  for (var i = 0; i < cell.length; i++) {
    cell[i].classList.add("over");
  }
  gameOver.classList.add("true");
  audioBomb.play();
});

Auch die Audiodateien werden über JavaScript eingebettet.


Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Entwicklung von Multimediasystemen (Sommersemester 2021, Amy Linh Hoang,  Prof. Dr.-Ing. Steinberg) entstanden. Verwendete Techniken sind HTML5, CSS3 und JavaScript. Die besten Tutorials stellen wir Euch hier in den nächsten Wochen nach und nach vor.

DOI: Ein digitaler Objektidentifizierer

Beitragsbild DOI

Autorin: Sabine Volkmer


In diesem Beitrag geht es hauptsächlich um die Frage:
Was ist ein digitaler Objektidentifizierer und wozu ist er gut?

Inhalt:

Offenbar muss heutzutage fast alles mit Hilfe einer Identifikationsnummer zugeordnet werden. Selbst der Mensch. Jeder kennt z. B. mehr oder weniger auswendig seine eigene, ihm individuell zugewiesene Steuer-, Matrikel- oder Personalausweisnummer. Im Bibliothekswesen und im speziellen bei den Büchern nennt sich diese ISBN (International Standard Book Number) und bei den Zeitschriften ISSN (International Standard Serial Number). Jeder, der sich auch nur sporadisch in Bibliotheken aufhält, hat diese gesehen. Jedoch weiß keiner so genau wie der DOI aufgebaut ist. Der DOI – ausgeschrieben als digitaler Objektidentifizierer verhält sich ähnlich wie eine ISBN/ISSN, weil er statt einem Buch oder einer Zeitschrift ein digitales Objekt eindeutig identifiziert.

Dieser Blogbeitrag handelt von der Geburtsstätte der DOI in den Registrierungsagenturen bis zum Zielobjekt – dem digitalen Objekt. Die drei Buchstaben „D-O-I“ stehen für „Digital Object Identifier“ (Digitaler Objektidentifizierer). Diese Identifikationsnummer gehört jeweils zu einem digitalen Objekt. Dies können u.a. Texte oder digitale Forschungsdaten sein. Aber wozu ist eine Zuordnung überhaupt nötig und warum werden DOIs für das wissenschaftliche Arbeiten so dringend gebraucht?

Studierende wissen, dass alle von ihm zitierten Stellen sich auch im Literaturverzeichnis wieder gefunden werden müssen. Da im wissenschaftlichen Bereich dauerhafte Zitatensicherheit gefordert ist und DOIs sich nicht wie URLs verändern, werden diese anstelle von URLs für Literaturverzeichnisse gemeinhin empfohlen. So können Belege auch nach Jahren überprüft werden, weil auf digitale Objekte nachhaltig und eindeutig zugegriffen werden kann. Jedoch ist dies nicht immer der Fall. So gesehen wird eine DOI für die Identifizierung von physischen, digitalen oder anderen Objekten benutzt und führt den Nutzer direkt zum endgültigen Speicherort des bezeichneten Objektes.

DOI-Vergabe

Es haben jedoch noch nicht alle akademischen Texte eine DOI Nummer auch erhalten und erst seit dem Jahre 2000 werden DOIs für Onlineartikel aus wissenschaftlichen Fachzeitschriften vergeben.[1]EBooks haben ebenfalls in den meisten Fällen eine DOI. Auch verwenden viele wissenschaftliche Verlage DOIs zur persistenten Adressierung ihrer Artikel.[2] Persistenz bedeutet in diesem Fall, dass das digitale Objekt überall wiedergefunden werden kann. Doch wie werden diese nun vergeben? Wird da gewürfelt oder einfach wilde Zahlenreihen ausgelost?

Die Vergabe von DOIs werden von einer amerikanischen Non-Profit-Gesellschaft betrieben. Inzwischen beträgt die Zahl der vergebenen DOIs mehrere Millionen. Die oberste Organisation der DOI ist die „International DOI Foundation“ (IDF). Diese vergibt Lizenzen an über 10 weltweite DOI-Registrierungsagenturen, von denen DOIs erworben werden können. Die wichtigsten Hauptagenturen sind: „Crossref“, „mEDRA“, „Datacite“ (scientific data sets). Von „DataCite“ wird der DOI-Registrierungsservice für Forschungsdaten zur Verfügung gestellt.[3] Die Verteilung der DOIs erfolgt ausschließlich durch die DOI-Registrierungsagenturen, die eine Lizenz von der IDF erworben haben. Somit kann sichergestellt werden, dass Standards von der IDF, eingehalten werden.

Innovation in Bibliotheken: Deichman Bibliothek Oslo

Beitragsbild Innovation in Bibliotheken

Autorin: Merle Stegemeyer


“Wir leben in einer postdigitalen Situation. Die Leute wollen sich wieder real begegnen, öffentliche Räume werden wieder wichtiger.”[4]

– Reinert Mithassel, Leiter der Biblio Tøyen

Reinert Mithassel, Leiter der Biblio Tøyen in Oslo, spricht damit wohl nicht nur die andauernde Corona Pandemie an, sondern äußert den Wunsch vieler Menschen ihrer Umgebung und ihren Mitmenschen wieder näher zu kommen. Auch wenn die Corona Pandemie uns sicherlich in Hinblick auf Digitalisierung in (Hoch-) Schulen und am Arbeitsplatz große Schritte nach vorn gebracht hat, vermissen und beklagen wir doch, wie sehr uns die sozialen Kontakte fehlen.

Wie aber kann öffentlicher Raum so gestaltet werden, dass Menschen hier Zeit verbringen wollen? Es sind dabei insbesondere die Biblio Tøyen und die 2020 neu eröffnete Bjørvika Bibliothek zu nennen. Sie zeigen uns zwei zukunftsweisende Wege wie das Bibliothekswesen aussehen kann.

Deichman Biblio Tøyen

Die eigentlich in einem Problemviertel liegende Jugendbibliothek Biblio Tøyen steht dem Neubau im entstehenden neuen Kulturhafen Oslos in nichts nach. In Zusammenarbeit mit jungen Osloern und dem niederländischen Architekten/Creative Guide Aat Vos wurde die Bibliothek neu eingerichtet und umgestaltet.[11] Die Idee hinter der Umgestaltung bestand darin, ein Kulturhaus zu schaffen, das Jugendlichen ihren Bezug zur Realität nicht verlieren lässt. Denn durch die immer schneller werdenden Modernisierungen und die rasante Entwicklung der Gesellschaft kann ein solcher öffentlicher Rückzugsort für Jugendliche einen Ankerplatz bieten.[11]

So entstanden in alten, ausrangierten Kleinlastern und Seilbahnkabinen kleine Oasen der Ruhe und Orte zum Lesen. Ebenso Nester aus Kissen oder umfunktionierte Schubkarren dienen als Plätze zum Entspannen oder zum Lesen. Des Weiteren verleihen die vielen schwebende Elemente diesem Ort eine unglaubliche Leichtigkeit.[8][11]

Eltern und Erwachsenen ist der Zugang ausdrücklich nicht erlaubt, sodass die 10- bis 15-Jährigen hier ihre ganz eigenen Erfahrungen mit ihrer Freiheit, Umgebung und eben den Büchern machen können. Diese dadurch entstehende Wohnzimmeratmosphäre dient der Inspiration und lässt seine jugendlichen Besucher viel Freiraum. Dies wird zudem dadurch unterstützt, dass die Räumlichkeiten der Biblio Tøyen auch ohne Bibliothekspersonal zugänglich sind. [8]

Begib Dich auf einen kleinen Rundgang durch die Biblio Tøyen.[6]

Makerspaces: Eine Aufgabe für Öffentliche Bibliotheken?

Beitragsbild Makerspaces – Eine Aufgabe für Öffentliche Bibliotheken?

Autorin: Janina Gerten


Ob das Konzept des Makerspace in das Aufgabenportfolio von Öffentlichen Bibliotheken passt, darüber herrschen unterschiedliche Meinungen. Was ein Makerspace überhaupt ist und welchen Mehrwert er Öffentlichen Bibliotheken bieten kann, soll anhand der „MachBar“ der Stadtbibliothek Duisburg in diesem Artikel verdeutlicht werden.

Inhalt

  1. Maker und Makerspaces
  2. Ausstattung und Angebot
  3. Makerspaces als Aufgabe von Öffentlichen Bibliotheken
  4. Anmerkungen und Quellen

“Öffentliche Bibliotheken waren in früheren Zeiten Ausleihstationen für Bücher und audiovisuelle Medien. Dieses Rollenverständnis hat sich in den vergangenen zwanzig Jahren erheblich verändert. Zum einen haben das Internet und der starke Ausbau der digital verfügbaren Medien das Spektrum der Nutzung, einschließlich der Erschließung von Informationen und Wissen, qualitativ erweitert.”

Dr. Jan-Pieter Barbian, Direktor der Stadtbibliothek Duisburg


Maker und Makerspaces

Die sogenannte Maker-Bewegung, deren Anfänge bereits 25 Jahre zurück liegt, bildet den Ursprung der heutigen Makerspaces. Der Grundgedanke des Teilens stand bereits damals im Vordergrund. Diese Philosophie greifen Makerspaces wieder auf, indem sie einen öffentlich zugänglichen Raum schaffen und entsprechende Ressourcen zur Verfügung stellen. Hier können Menschen zusammenkommen, um etwas zu „machen“ und ihre Ideen mithilfe von analogen sowie digitalen Werkzeugen umzusetzen.5 Ebenfalls der Aspekt der Nachhaltigkeit spielt dabei eine wichtige Rolle, da oftmals gebrauchte Materialien wiederverwendet und so Ressourcen geschont werden. Dabei geht es jedoch nicht nur um die gemeinschaftliche Nutzung von Ressourcen, sondern auch um den Austausch von Wissen, Kompetenzen und Ideen sowie gemeinsam Neues auszuprobieren und zu entwickeln.4 Die Stadtbibliothek Duisburg hat es für sich wie folgt definiert:

“Die MachBar soll dem gemeinsamen Arbeiten in einer kreativen Umgebung dienen und Hemmschwellen gegenüber neuen Technologien abbauen. Dafür stellen wir unseren Nutzerinnen und Nutzern in einem offenen Raum eine moderne technische Ausstattung zur Verfügung. Sie können neue Techniken ausprobieren, eigene Projekte verwirklichen, Erfahrungen austauschen und Gleichgesinnte treffen.”

Tutorial: Ein Memory-Spiel

Beitragsbild Tutorial: Memory-Spiel

Autorin: Linda Görzen 


Memory-Spiel

Konzept

Ziel dieses Projektes war die Erstellung eines Spiels , das durch sämtliche Animationen bzw. Animationseffekte modern und dynamisch wirken sollte. Memory ist ein Spiel, das weltbekannt und nicht zu kompliziert zu programmieren ist. Im Internet gibt es sämtliche frei verfügbare Beispielcodes. Einer davon wurde in diesem Projekt verwendet.

Der Spielvorgang läuft folgendermaßen ab: Der Start des Spieles muss durch das Klicken eines Buttons ausgelöst werden. Danach hat man 30 Sekunden Zeit, um das Spiel zu gewinnen. Wenn man es nicht schafft, bricht das Spiel nach 30 Sekunden ab und man hat somit verloren.

Inhaltsverzeichnis

Aufbau

Das Spiel besteht aus drei Ebenen: 1. Startbildschirm 2. Spiel 3. Endbildschirm: gewonnen oder verloren

Für die Einfachheit und Übersichtlichkeit besteht das Spiel aus zwei HTML-Dateien. Die Datei game_start.html beinhaltet die erste Ebene. Die Datei game.html die Ebenen zwei und drei.

Startbildschirm

Hier erscheinen nacheinander ein Button, der zum Spiel weiterführen soll, ein Austronaut und ein Raumschiff. Im Hintergrund bewegen sich von oben nach unten und von unten nach oben kleine Punkte, die Sterne repräsentieren sollen. Der Button hat einen Hover-Effekt: Wenn man über ihn mit der Maus fährt, verändert sich der Text und die Farbe .

Memory-Spiel Bild 1
Abbildung 1: Startansicht

Memory-Spiel

Das eigentliche Spiel befindet sich im rechten Drittel des Bildschirms und besteht aus zwölf Karten, welche in drei Reihen gestapelt sind. Links vom Spiel sieht man den Astronauten und eine Sprechblase. Über den Astronaut schwebt ein Button, mit dem das Spiel neu gestartet werden kann. Beim Klicken auf die Karten, erscheint zusätzlicher Text in der Sprechblase. Nach ein paar Sekunden verschwindet dieser.

Memory-Spiel Bild 2
Abbildung 2: Spiel

Gewonnen – Endbildschirm

Wenn man innerhalb der 30 Sekunden alle Paare gefunden hat, verschwinden die Sprechblase und die Karten. Stattdessen blendet das Programm Konfetti und Überschrift “6/6! Gut gemacht gemacht!” ein. Im Hintergrund wird einmalig Triumpfsound “Ta-Da” abgespielt.

Memory-Spiel Bild 3
Abbildung 3: Spiel gewonnen

Verloren – Endbildschirm

Wenn 30 Sekunden verstrichen sind und nicht alle Paare gefunden wurden, dann bricht das Spiel ab und statt der Sprechblase und der Karten erscheint die Überschrift “Verloren” und in der Sprechblase steht jetzt “Schande!”. Der Astronaut fängt zu weinen an.

Memory-Spiel Bild 4
Abbildung 4: Spiel verloren

Erläuterung des Codes

Erste Ebene

HTML und javascript

Für die Erzeugung bestimmter Animationen lohnt es sich auf JS-Bibliotheken zurückzugreifen. In diesem Projekt wurde GSAP eingesetzt. Bei GSAP handelt es sich um eine JS-Bibliothek für zeitleistenbasierte Animationen . Die GSAP Funktionen lassen sich über CDN laden, indem man ihn im Head-Bereich einbindet.

Der CDN für allgemeine Funktionen reicht aber nicht aus, um Bewegung entlang eines vorgeschriebenen Pfades zu erzeugen. Der Code muss zusätzlich mit dem Plugin für GSAP-MotionPath ergänzt werden.

  <head>
    <meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="description" content="Memory game done with javascript and css animation">
    <meta name="keywords" content="game, interactive, avascript, css, html">
    <title>Memory Game</title>
	<link rel="stylesheet" href="styles_start.css"> <!-- Nur für game_start -->
	<script src="https://cdn.jsdelivr.net/web-animations/latest/web-animations.min.js"></script> <!-- Polyfill -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.0/gsap.min.js"></script> <!-- Core Green Sock-->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.0/MotionPathPlugin.min.js"></script> <!--Plugin für MotionPath von Green Sock-->
  </head>

Der HTML-Grundgerüst der ersten Ebene ist simpel aufgebaut. Es wurden nacheinander Elemente eingefügt, die in bestimmten Reihenfolge sichtbar werden sollten.

	<div class="sternenhimmel-bild">	
		<!-- Sterne, die sich von unten nach oben und umgekehrt bewegen, insperiert von https://www.youtube.com/watch?v=aywzn9cf-_U  -->
				<div id="stars"></div>
				<div id="stars2"></div>
				
				<div id="stars_2"></div>
				<div id="stars2_2"></div>	
			<img id="astro" src="Bilder/astro.png">
		
			<div>
				<a href="game.html"><button id="button1"></button></a>
			</div>
			
			<img id="spaceship" src="Bilder/futurama.png">
	</div>

Auf der ersten Ebene befindet sich der Javascript-Code in der HTML-Datei . Dank GSAP kann man den Code für die schwebende Bewegung des Astronauten kurz halten. Mit GSAP wird auch das Erscheinen des Buttons animiert. Man darf nicht vergessen den MotionPathPlugin zu registrieren, sonst wird motionPath nicht ausgeführt. Mit gsap.timeline() geben wir die Reihenfolge der Animationen vor. Zuerst soll der Button und dann der Astronaut erscheinen. Der Astronaut soll daraufhin im Kreis um den Button schweben und dann stehen bleiben.

		<script>
				//Plugin registrieren
				gsap.registerPlugin(MotionPathPlugin);
				
				//#astro 
				gsap.timeline().from('#button1', {opacy: 0.05, scale: 0, rotation: 10, ease:'back', duration: 1.5, })
							   .from("#astro", {duration: 2, x: 200, opacity: 0, scale: 0.5, rotation: 10})
							   .to("#astro", {
							  duration: 13, 
							  motionPath:{
							  path: [{x:220, y:440, scale:0.5, rotation:10}, {x:780, y:240,scale: 0.7, rotation:-30}, {x:470, y:10, scale:1, rotation:5}]
							  }
							});

				MotionPathHelper.create("#astro")
		</script>
CSS

Der Inhalt des Buttons wurde mit dem Pseudoelement ::after eingefügt. Das Ziel war es, den Text beim Hovern über den Button zu ändern. Beim Hovern sollen auch die Hindergrundfarbe und der Schatten sich verändern. Da :hover::after nur den Inhalt (also Text) ansteuert, muss man noch einmal :hover benutzen.

#button1 {
	display:inline-block;
	box-sizing: border-box;
	min-width: 11em;
	border-width: 4px;
	border-radius: 20px;
	background-color: rgba(204, 102, 255, 0.55);
	border-color: rgba(239, 204, 255);
	text-align: center;
	font-size: 31px;
	padding: 25px;
	position: absolute;
	top: 53%;
	left: 50%;
	transform: translate(-50%, -50%);
	box-shadow: 0 8px 16px 0 rgba(0,0,0,0.3), 0 6px 20px 0 rgba(0,0,0,0.29);
}

#button1::after{
    content:'Eine Runde spielen?';
}
#button1:hover::after{
    content:"Los geht's!";
}

#button1:hover {
    background-color: rgba(251, 41, 253, 0.9);
    cursor: pointer;
      box-shadow: 0 8px 70px 0 rgba(255,250,250,0.3), 0 8px 70px 0 rgba(255,250,250,0.3),  0 8px 70px 0 rgba(255,250,250,0.3), 0 8px 70px 0 rgba(255,250,250,0.3);
    transition: background-color 2s ease-out;
}

Um den Hintergrund dynamischer wirken zu lassen, werden zwei Sterne-Animationen hinzugefügt. Die Idee der Erstellung der Sterne mit box-shadow und sie dann in Bewegung zu setzten stammt von diesem Youtube-Video . Im Spiel bewegen sich die Sterne sowohl von oben nach unten als auch von untern nach oben. Ermöglicht wird es durch zwei Keyframes.

/* von unten nach oben */
#stars {
	width: 3px;
	height: 3px;
	border-radius: 50%;
	background:transparent;
	animation: animStar 50s linear infinite;
	box-shadow: 789px 1341px #fff, 
				364px 52px #fff, 
				353px 596px #fff,
				1412px 376px #fff, 
				451px 625px #fff, 
				521px 1931px #fff, 
				1087px 1871px #fff,
				36px 1546px #fff, 
				132px 934px #fff, 
				1698px 901px #fff, 
				1418px 664px #fff,
				1448px 1157px #fff,
				1084px 232px #fff, 
				347px 1776px #fff, 
				1222px 343px #fff; /* 15*/
}

#stars2 {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background:#bb33ff;
	animation: animStar 100s linear infinite;	 
	box-shadow: 1448px 320px #00ffff, 
				1775px 1663px #00ffff, 
				332px 1364px #00ffff,
				878px 340px #00ffff, 
				569px 1832px #00ffff,
				1422px 1684px #00ffff, 
				1946px 1907px #00ffff,
				121px 979px #00ffff, 
				1044px 1069px #00ffff, 
				463px 381px #00ffff, 
				
				423px 112px #ffffb3,
				523px 1179px #ffffb3, 
				779px 654px #ffffb3,
				1398px 694px #ffffb3, 
				1085px 1464px #ffffb3;
}

@keyframes animStar{
	from {
		transform: translateY(0px);
	}
	to {
		transform: translateY(-1000px);
	}
}


/* von oben nach unten*/

#stars_2 {
	width: 3px;
	height: 3px;
	border-radius: 50%;
	background:transparent;
	animation: animStar_2 50s linear infinite;
	box-shadow: 779px 1331px #fff, 
				324px 42px #fff, 
				303px 586px #fff,
				1312px 276px #fff, 
				451px 625px #fff, 
				521px 1931px #fff, 
				1087px 1871px #fff,
				36px 1546px #fff, 
				132px 934px #fff, 
				1698px 901px #fff, 
				1418px 664px #fff,
				1448px 1157px #fff,
				1084px 232px #fff, 
				347px 1776px #fff, 
				1722px 243px #fff; /* 15*/
}

#stars2_2 {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background:#bb33ff;
	animation: animStar_2 100s linear infinite; 
	box-shadow: 1448px 320px #9acd32, 
				1775px 1663px #9acd32, 
				332px 1364px #9acd32,
				878px 340px #9acd32, 
				569px 1832px #9acd32,
				1422px 1684px #9acd32, 
				1946px 1907px #9acd32,
				121px 979px #9acd32, 
				1044px 1069px #9acd32, 
				463px 381px #9acd32, 
				
				423px 112px #ffffb3,
				523px 1179px #ffffb3, 
				779px 654px #ffffb3,
				1398px 694px #ffffb3, 
				1085px 1464px #ffffb3;
}

@keyframes animStar_2{
	from {
		transform: translateY(-1000px);
	}
	to {
		transform: translateY(1000px);
	}
}

Die Animation des Raumschiff ist ähnlich wie bei den Sternen umgesetzt. Die Keyframes teilen wir dieses Mal in Prozente ein.

#spaceship{
	animation-delay: 4s;
	animation: futurama 10s linear forwards;
}

@keyframes futurama{
	0% {
		max-width: 1%; 
		transform: translateX(-20em);
	}
	25% {
		max-width: 4%; 
	}
	100% {
		transform: translateX(-10em);
		max-width: 14%; 
	}
}

Zweite Ebene

HTML

Für die zweite Ebene, also für die Datei game.html , fügen wir im Head-Bereich zusätzlich zu GSAP ein Script von LottieFiles hinzu . Dieser ermöglicht später eine Lottie-Animation zu starten.

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.0/gsap.min.js"></script> <!--Green Sock-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.0/MotionPathPlugin.min.js"></script> <!--Green Sock-->		 

<script src="https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js"></script> <!-- Lottiefiles-->

Der HTML-Code ist auch hier unkompliziert gestaltet. Der Div mit der class=”grid” ist der wichtigste Bestandteil dieses HTML-Codes. Über ihn erzeugt die app.js-Datei die Memory-Karten .

Bei der Lottie-Animation handelt es sich um eine Konfetti-Animation, die nur beim Gewinnen des Spiels über Javascript aktiviert wird. Sie ist in der HTML-Datei über den <lottie-player>-Tag eingebunden und über CSS angepasst.

<!-- Memory-Spiel -->
    <div class="grid"></div> <!-- Memorykarten werden über app.js erzeugt -->   

    <img id="gameAstro" src="Bilder/astro.png"/>        <!-- Astronaut -->
    <img id='Traene' src='Bilder/water.svg'> <!-- erscheint, wenn verloren -->
    <div id="score" >
        <h3>
            Du hast 30 Sekunden Zeit <br/> 
            Dein Score:<span id="result"></span>
        </h3>
        <p id="message"></p>
    </div>


<!--Spiel gewonnen-->
<lottie-player src="https://assets6.lottiefiles.com/packages/lf20_u4yrau.json" id='confetti' background="transparent"  speed="1.15"    loop  autoplay></lottie-player>
<div id='gewonnen'><h1>6/6! Gut gemacht!</h1></div>


<!--Spiel verloren-->    
<div id="Schande"><p>Schade!</p></div>
<div id='verloren'><h1>Verloren</h1></div>


<!-- "Neues Spiel"  Button -->  
<a href="javascript:location.reload()"><div id="nochMal">Neues Spiel</div></a>
Javascript

Der grundlegende JS-Code für das Memory-Spiel stammt aus diesem YouTube-Video. Der Code wurde modifiziert und an eigene Bedürfnisse angepasst.

Das Programm führt folgende Schritte aus: createBoard() kreiert innerhalb des .grid-Divs Child-Elemete, die für die Erstellung der Karten benötigt werden. Timer löst nach 30 Sekunden die Funktion verloren() aus, die die Elemente .grid und und scoreDiv entfernt und stattdessen andere Elemente aktiviert. Die Funktion checkForMatches() erfüllt gleich mehrere Aufgaben: Sie vergleicht die angeklickten Karten und je nach Auswahl gibt einen Text in der Sprechblase aus. Wenn sie feststellt, dass alle Paare gefunden wurden, löscht bzw. deaktiviert sie bestimmte Elemente und blendet neue ein. Die flipCard()-Funktion sorgt dafür, dass die Karten “umgedreht” werden und man das verborgene Bild sieht. Es können nur zwei Karten gleichzeitig umgedreht werden.

document.addEventListener('DOMContentLoaded', () => {

  //Kartenauswahl
  
  const cardArray = [
    {
      name: 'mond',
	  img: 'Bilder/mond.svg'
    },
    {
      name: 'alien',
	  img: 'Bilder/alien.svg'
    },
    {
      name: 'ufo',
	  img: 'Bilder/ufo.svg'
    },
    {
      name: 'rocket',
	  img: 'Bilder/rocket.svg'
    },
    {
      name: 'space',
      img: 'Bilder/space.svg'
    },
    {
      name: 'sun',
      img: 'Bilder/sun.svg'
    },
    {
      name: 'mond',
      img: 'Bilder/mond.svg'
    },
    {
      name: 'alien',
      img: 'Bilder/alien.svg'
    },
    {
      name: 'ufo',
      img: 'Bilder/ufo.svg'
    },
    {
      name: 'rocket',
      img: 'Bilder/rocket.svg'
    },
    {
      name: 'space',
      img: 'Bilder/space.svg'
    },
    {
      name: 'sun',
      img: 'Bilder/sun.svg'
    }
  ];

  cardArray.sort( () => 0.5 - Math.random());
  

  const grid = document.querySelector('.grid');
  const resultDisplay = document.querySelector('#result');
  const wordCloud = document.querySelector('#message');
  const scoreDiv = document.querySelector('#score');
  const gameAstro = document.querySelector('#gameAstro');
  
  let cardsChosen = [];
  let cardsChosenId = [];
  let cardsWon = [];
  
  //create your board

  function createBoard() {
    for (let i = 0; i < cardArray.length; i++) {
	const cardDiv = document.createElement('div') //Um die karten herum einen Div erstellen
	cardDiv.setAttribute('class', 'imgDiv') //Um die karten herum einen Div erstellen
	
    const card = document.createElement('img')
	card.setAttribute('class', 'Spielbilder')
    card.setAttribute('src', 'Bilder/logo.svg')
    card.setAttribute('data-id', i)
    card.addEventListener('click', flipCard)
	  
	grid.appendChild(cardDiv).appendChild(card) //Um die Karten herum einen Div erstellen
    }
  };
  
    
  //Timer. Falls das Spiel mach 30 Sekunden nicht gewonnen wurde, wird das Spiel abgebrochen
  	var timer = setTimeout( function(){verloren();}, 30000);
	function verloren(){
	  grid.remove()
	  scoreDiv.remove()
	  gameAstro.style.marginTop = '17em'
	  gameAstro.style.marginLeft = '7em'
	  gameAstro.style.width = '10em'
	  
	  document.querySelector('#verloren').style.display = 'block'
	  document.querySelector('#Schande').style.display = 'block'
	    
	  gsap.timeline().from("#gameAstro", {duration: 2, y: 200, opacity: 0, scale: 0, rotation: 180, ease:'back'});
	  
	  document.querySelector('#Traene').style.display = 'block'
	};
  

  //check for matches
  function checkForMatch() {
    const cards = document.querySelectorAll('img')
    const optionOneId = cardsChosenId[0]
    const optionTwoId = cardsChosenId[1]
	
    
    if(optionOneId == optionTwoId) {
      cards[optionOneId].setAttribute('src', 'Bilder/logo.svg')
      cards[optionTwoId].setAttribute('src', 'Bilder/logo.svg')
	  wordCloud.textContent = 'Du hast die gleiche Karte angeklickt!'
	  setTimeout(function(){ wordCloud.innerHTML=''; }, 2000); //Nach 2000 ms den text aus der Sprechblase entfernen
    }
    else if (cardsChosen[0] === cardsChosen[1]) {
	  wordCloud.textContent = 'Du hast ein Paar gefunden!'
	  setTimeout(function(){ wordCloud.innerHTML=''; }, 2000); //Nach 2000 ms den text aus der Sprechblase entfernen
      cards[optionOneId].removeAttribute('src', 'Bilder/logo.svg')
      cards[optionTwoId].removeAttribute('src', 'Bilder/logo.svg')
      cards[optionOneId].removeEventListener('click', flipCard)
      cards[optionTwoId].removeEventListener('click', flipCard)
      cardsWon.push(cardsChosen)
    } else {
      cards[optionOneId].setAttribute('src', 'Bilder/logo.svg')
      cards[optionTwoId].setAttribute('src', 'Bilder/logo.svg')
	  wordCloud.textContent = 'Schade, versuch es noch mal'
	  setTimeout(function(){ wordCloud.innerHTML=''; }, 2000); //Nach 2000 ms den text aus der Sprechblase entfernen
    }
    cardsChosen = []
    cardsChosenId = []
    resultDisplay.textContent = cardsWon.length
	var audio = new Audio('ta-da.mp3');
    if  (cardsWon.length === cardArray.length/2) {
      //Falls das Spiel innerhalb von 30 Sekunden gewonnen:
	  clearTimeout(timer)  //Timer aussetzen, damit das Spiel nicht abgebrochen wird
      audio.play();
	  grid.remove()
	  scoreDiv.remove()
	  gameAstro.style.marginTop = '17em'
	  gameAstro.style.marginLeft = '7em'
	  gameAstro.style.width = '10em'
	  
	  document.querySelector('img#gameAstro').style.animationName = 'none' //Animation entfernen, damit GreenSock-Animation abgespilt werden kann
	  document.querySelector('#gewonnen').style.display = 'block'
	  document.querySelector('#confetti').style.display = 'block'
	  
	  //Freudiges Springen
	  gsap.timeline().from("#gameAstro", {duration: 2, y: 200, opacity: 0, scale: 0, rotation: 180, ease:'back'})
					.to('#gameAstro', { duration: .25, y: -50,  repeat: -1, yoyo: true, ease: "sine.inOut", autoRound: false}); 
    }
  };

  //flip your card
  function flipCard() {
	
    let cardId = this.getAttribute('data-id')
    cardsChosen.push(cardArray[cardId].name)
    cardsChosenId.push(cardId)
    this.setAttribute('src', cardArray[cardId].img)
    if (cardsChosen.length === 2) {
      setTimeout(checkForMatch, 300)
    }
  };

	createBoard();
});
css

Das Aussehen der Karten wird über die Klassen .grid , .imgDiv und .Spielbilder bestimmt. Die Klasse .grid ist für die Verteilung der Karten auf dem Bildschirm zuständig. Hier empfielt es sich, die Einstellung display:flex zu wählen. Es ist der leichteste Weg ist, die Karten zu positionieren. Für die richtige Reihung der Karten ist es wichtig, dass die Breite des .grid-Containers und die Breite der einzelnen Karten, die von .imgDiv gesteuert werden, auf einander abgestimmt sind.

/* Während des Spiels*/

.grid{
	display: flex;
	flex-wrap: wrap;
	width: 30em;
	margin-right: 5em;
	margin-top: 3em;
	float:right;

}

.imgDiv {
	background-color: rgba(204, 102, 255, 0.55);
	border-radius: .25em;
	width:7em;
	height:12em;
	margin:.25em;
	box-shadow: rgba(50, 50, 93, 0.65) 0px 50px 100px -20px, rgba(0, 0, 0, 0.6) 0px 30px 60px -30px, rgba(10, 37, 64, 0.65) 0px -2px 6px 0px inset;	
}
.imgDiv:hover {
	box-shadow: rgba(153, 255, 102, 0.65) 0px 50px 100px -20px, rgba(0, 0, 0, 0.6) 0px 30px 60px -30px, rgba(153, 255, 102, 0.65) 0px -2px 6px 0px inset;	
}
img.Spielbilder { 
	max-height:100%; 
	max-width:100%;
	padding:1em;
}

Dritte Ebene

Die einzelnen Elemente der dritten Ebene werden je nach Ergebnis des Spieles durch den JS-Code aktiviert. Aus diesem Grund sind sie alle mit display:none versehen. Der JS-Code verändert sie dann mit document.querySelector zu display:block.

/* Spiel gewonnen*/
h1 {
	font-size: 5em;
}

#gewonnen {
     animation: Schweben 5s linear easy-in;
    display: none;
    position: absolute;
    left: 53em;
    top: 20em;
    z-index: 10;
}
#confetti{
	display: none;
	width:75em;
	height: auto;
	float: right;
}
/* Spiel verloren*/
#verloren {
	display: none;
	animation: Schweben 6s linear infinite;
    position: absolute;
    left: 53em;
    top: 20em;
    z-index: 10;
	float:left;
}
#Schande {
	display: none;
	animation: Schweben 13s linear infinite;
	clip-path: polygon(0% 0%, 100% 0%, 100% 75%, 69% 75%, 5% 100%, 27% 76%, 0% 75%);
	width: 16em;
	height:9em;
	margin-top: 13em;
	margin-left:4em;
	padding: 1em;
	float: left;	
	background-color: rgba(204, 102, 255, 0.55);
}
#Schande p {
	font-size: 2em;
	text-align: center;
}

#Traene {
	display: none;
	width: 0em;
	position:absolute;
    left: 12.5em;
	top: 22em;
	z-index: 15;
	animation: traene 3s linear infinite;
	transition: ease-in;
	animation-delay: 3s;
}
@keyframes traene{
	from {
		transform: translateY(0em);
		width: 0.5em;
	}
	to {
		transform: translateY(13em);
		width: 3em;

	}
	to {
		transform: translateY(15em);
	}
	to {
		transform: translateY(16em);
		opacity: 60%;
	}
	to {
		transform: translateY(17em);
		opacity: 7%;
	}
}

Sowohl in der zweiten als auch in der dritten Ebene werden alle sichtbaren Elemente (bis auf die Memory-Karten) mit einer Schwebeanimation versehen, um den Eindruck zu vermitteln, dass die Objekte wie im echten Weltall schweben.

/*Alles soll schweben*/
@keyframes Schweben {
	0% {

		transform: translatey(0px);
	}
	25%{
		transform: translatex(-5px);
	}
	50% {

		transform: translatey(-10px);
	}
	100% {

		transform: translatey(0px);
	}

}

Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Entwicklung von Multimediasystemen (Sommersemester 2021, Amy Linh Hoang,  Prof. Dr.-Ing. Steinberg) entstanden. Verwendete Techniken sind HTML5, CSS3 und JavaScript. Die besten Tutorials stellen wir Euch hier in den nächsten Wochen nach und nach vor.

Tutorial: Ein Tag mit Bobby

Beitragsbild Tutorial zur Animation: Ein Tag mit Bobby

Autor*in: Julia Solohub 


Animation anschauen

Quellcode (Zip-Archiv zum Download)

Dieser Beitrag ist ein Tutorial zu der Animation „Ein Tag mit Bobby“ bei dem auf die Details zum Code, Inhalt, Besonderheiten, das Konzept und Schwierigkeiten eingegangen wird. Die Bilder dienen zur Veranschaulichung und Nachvollziehbarkeit und sind anklickbar, sodass man diese in Vollbildmodus und besserer Auflösung betrachten kann.

Inhaltsverzeichnis

Das Konzept

Die Animation ist ein Storytelling, bei dem der User mit Hilfe von Buttonklicks durch die einzelnen Szenen geleitet wird.  Dieser begleitet den Hauptcharakter Bobby durch den Tag und führt verschiedene Anweisungen durch, die Bobby in der Sprechblase gibt. Diese können durch einen Buttonklick realisiert werden. Sobald der User auf einen Button klickt, wird entweder die Szene gewechselt oder ein visueller Effekt erzeugt.

Das Ziel ist es mit dem User eine Interaktion zu starten, wobei dieser den Ablauf der Animation lenkt. Der User wird zu Beginn auch direkt von Bobby mit dem Namen angesprochen und aufgefordert mit ihm den Tag zu verbringen.

Die Idee eine Animation mit Hund(en) zu erstellen, kommt von der persönlichen Liebe zu Tieren und insbesondere zu Hunden. Die kindliche und amüsante Darstellung soll den User animieren und erfreuen. Die Hintergrundmusik sorgt für eine zusätzliche entspannte Atmosphäre, die die Stimmung der Animation unterstützt. Der User kann sich somit entspannen, zurücklehnen und die Animation genießen.

Aufbau

Die Animation ist in vier Szenen aufgeteilt:

  1. Start-Szene (div class=“ story_start_scene“)
  2. Bobby im Wohnzimmer (div-class= „dog_in_livingroom_scene“)
  3. Bobby im Park (div class=”background_image_park_day”)
  4. Schluss-Szene bei der Bobby im Park nachts ist (div class=”dog_in_park_night”)

Start Szene

Bei der Start Szene sieht man den schlafenden Bobby auf einem Teppich ohne jeglichen Hintergrund, das sich zu den restlichen Szenen unterscheidet. Der Grund dafür ist, dass man zum einen den beweglichen und farbwechselnden Hintergrund auf sich wirken lassen kann und zum anderen sollte es schlicht gehalten werden, damit der Wechsel zu den Hauptszenen spannender gestaltet wird. Zudem soll der Fokus zu Beginn auf dem Hauptcharakter liegen. Mit dem Buttonklick auf „Aufwecken“ startet die ganze Animation.

Start Szene

Zweite Szene

In der zweiten Szene befindet sich Bobby im Wohnzimmer, wo er zuvor auf dem Teppich geschlafen hat. Der User hat ihn aufgeweckt und nun fragt Bobby ihn nach seinem Namen. Die Abfrage passiert zwischen der ersten und der zweiten Szene, die mit Hilfe von JavaScript erzeugt wurde. Je nachdem welchen Namen der User eingibt, erscheint dieser in dem Begrüßungstext in der Sprechblase. Hier wird der User aufgefordert die Anweisungen von Bobby durchzuführen. In dieser Szene soll der User mit Bobby in den Park gehen.

Zweite Szene
Zweite Szene

Dritte Szene

Die dritte Szene spielt sich im Park tagsüber ab in den mehrere Aktionen passieren. Zu Beginn sieht man den Park, in dem sich ein Grill und Bobby befinden. Bobby weist darauf hin, dass es vom Grill sehr gut riecht und er gerne einen Hot Dog haben möchte. Dieser Bitte kann der User nachgehen, indem er auf den langsam erscheinenden Button „Hot Dog geben“ klicken kann. Sobald dies gemacht wurde, erscheint ein animierter Hot Dog, der vom Grill aus zu Bobby in einer 360 Grad Drehung geworfen wird. Daraufhin bedankt sich Bobby und gibt den nächsten Hinweis, dass er seinen Freund Bello sieht und mit ihm Ball spielen möchte.

Dritte Szene
Dritte Szene

Auch hier kann der User der Anweisung nachgehen, indem er auf den nächsterscheinenden Button „Mit Bello spielen“ klickt. Hier erfolgt die nächste Animation, bei der sich Bello und Bobby den Ball zu werfen. Dabei springen beide versetzt hoch und werfen den Ball mit ihrem Kopf einander zu. Nun erscheint der fünfte Button „Weiter“, der den User darauf hinweist, dass danach die nächste Szene erscheint.

Vierte Szene

Vierte Szene
Vierte Szene

Die vierte und letzte Szene findet in dem selben Park statt. Jedoch ist es schon spät geworden und Bobby ist müde. Er macht vor Freude Rückwärtssaltos und bedankt sich für den großartigen Tag, den er mit dem User erlebt hat. Auch hier weist Bobby daraufhin, dass er müde und erschöpft ist. Hier ist es Zeit sich von Bobby zu verabschieden und ihm eine Gute Nacht zu wünschen.

Letzte Szene
Letzte Szene

Mit dem Buttonklick kann man dies tun, wobei das Bild von Bobby in den ursprünglich schlafenden Zustand zurückgebracht wird. Es taucht ein Eyecatcher auf, der zoomt und sich hin und her in verschiedene Winkel dreht. Dies ist der Abschluss der Animation, der durch den animierten Text „Gute Nacht, Bobby“ kenntlich gemacht wird. Der letzte Button unterscheidet sich in der Erscheinungsweise von allen anderen, denn dieser macht auf sich Aufmerksam, indem sich dieser hin und her bewegt und dabei vertikal spiegelt. Der Grund für diese Erscheinungsweise ist das Aufmerksam machen, dass ab hier keine neue Szene erscheint, sondern alles nochmal vom Anfang beginnt. Somit ermöglicht dieser Button die Animation nochmal neu zu starten

Der Code

Für die Animationen wurden HTML5, CSS3 sowie JavaScript und jQuery benutzt. HTML5 wurde für das Grundgerüst und Aufbau, CSS3 für die Animation sowie das Styling und JavaScript bzw. jQuery für das Auslösen/Verstecken verschiedener Animationsobjekte benutzt.

Allgemeine Einstellungen

In der ID „animation_start“ in HTML5 spielt sich die gesamte Animation ab. Die jeweiligen Szenen sind in einzelne div-classes unterteilt in denen die dazugehörigen Objekte enthalten sind. Die div-classes sind nach den Szenarien benannt, das das Erkennen der Inhalte vereinfacht.

<div id="animation_start"class="whole_animation"> <!--ID der gesamten Animation-->
      <div class="story_start_scene"><!--Erste Szene: Startbildschrim-->
         <img src="sleeping_dog.png" id="sleep"/>
         <img src="carpet.png" id="carpet"/>
       </div>
    
       <div class="dog_in_livingroom_scene"> <!---Zweite Szene: Bobby im Wohnzimmer Szene samt Begrüßung-->
          <div class="living_room_background">
            <img src="room.png" class="backgroundimage_livingroom" style="visibility: hidden;"/>
           </div> 
           <div class="dog_character">
             <img src="standing_dog.png" id="hello_dog" style="visibility: hidden;"/>
             <img src="sprechblase.png" id="speak1" style="visibility: hidden;"/> 
             <p id="welcome_text" style="visibility: hidden;">Hallo! Ich bin Bobby. Lass uns den Tag zusammen verbringen.</p>
           </div>
       </div>

       <div class="dog_in_park_day"> <!--Dritte Szene: Bobby im Park Szene mit dazugehörigen Objekten-->
           <div class="background_image_park_day">
             <img src="meadow_at_day.png" class="backgroundimage_park_day" style="visibility: hidden;"/>        
           </div>
           <div class="park_items">
             <img src="grill.png" id="bbq" style="visibility: hidden;"/>
             <img src="food.png" id="hot_dog" style="visibility: hidden;"/>
             <img src="standing_dog2.png" id="dog_at_park" style="visibility: hidden;"/>
             <img src="sprechblase2.png" id="speak2" style="visibility: hidden;"/>
             <p id="hot_dog_text" style="visibility: hidden;">Das riecht aber toll! Kannst du mir einen Hot Dog geben?</p>
             <p id="thank_you_hot_dog_text" style="visibility: hidden;">Danke! Ouh Schau! Da ist Bello. Ich möchte mit ihm Ball spielen.</p>
             <img src="playing_dog_brown.png" id="bello" style="visibility: hidden;"/>
             <img src="playing_dog_grey.png" id="bobby" style= "visibility: hidden;"/>
             <img src="ball.png" id="toy" style="visibility: hidden;"/>    
           </div> 
       </div>

       <div class="dog_in_park_night"><!--Abschlussszene: Bobby im Park nachts.--> 
           <div class="background_image_park_night">
             <img src="meadow_at_night.png" id="backgroundimage2" style="visibility: hidden;"/> 
             <img src="dog_by_night.png" id="night_dog" style="visibility: hidden;"/>
             <img src="sprechblase3.png" id="speak4" style="visibility: hidden;"/>
             <img src="sleeping_dog2.png" id="tired" style="visibility: hidden;"/>  
             <p id="thank_you_for_the_day" style="visibility: hidden;">Danke dir für den schönen Tag! Ich bin jetzt aber müde.</p>
             <p id="good_night_bobby" style="visibility: hidden;">Gute Nacht, Bobby</p>
           </div>
       </div>
 </div><!--Ende der "animation_start"-->

In der aside-class wurden alle Buttons und der Titel der der Animation eingetragen, da diese Inhalte sich immer an der selben Position befinden.

<body>
  <!--Alle Elemente sind auf "visibility:hidden" gesetzt, die über JavaScript aktiviert werden, wenn man auf einen Button klickt-->
  <script src="animation_functions.js"></script> <!--Einbindung der JavaScript Datei-->
  <aside class="title_and_buttons"> <!--Übergreifende Class für alle Buttons und Titel der Animation (h1) damit die Position die selbe bleibt-->
    <h1> Ein Tag mit Bobby</h1>
    <button id="button_aufwecken">
       <a class="button_1">Aufwecken</a>
    </button>
    <button id="button_park" style="visibility: hidden;">
      <a class="button_2">Lass uns in den Park gehen</a>
   </button>
   <button id="button_hot_dog" style="visibility: hidden;">
      <a class="button_3">Hot Dog geben </a>
    </button>
    <button id="button_play" style="visibility: hidden;">
      <a class="button_4">Mit Bello spielen</a>
    </button>
    <button id="button_next" style="visibility: hidden;">
     <a class="button_5">Weiter</a>
   </button>
   <button id="button_good_night" style="visibility: hidden;">
     <a class="button_6">Gute Nacht!</a>
  </button>
   <button id="button_reload" style="visibility: hidden;">
     <a class="button_7">Neustart</a>
 </button>
</aside> 

Auffallend im Code ist, dass alle Objekte nicht sichtbar sind (visibility: hidden). Diese werden zu dem Zeitpunkt wann die jeweiligen Objekte zu sehen sein sollen mit Hilfe von jQuery sichtbar gemacht. Die allgemeine Position aller Elemente ist in der ID „animation“ sowie dessen class „whole_animation“ zu sehen. So entsteht ein Rahmen für die verschiedenen Bilder, das die Zentrierung der Szenen möglich macht. Die gewählte Größe und Position erstellt eine Box, wo sich die Animation abspielt. Dies soll ein Gefühl erzeugen, als würde man in einem Kino vor einer Leinwand sitzen.

#animation { /*Ausrichtung der gesamten Animation*/
  align-items: center;
  min-height: 100%;
  position: absolute;
}

.whole_animation {
  max-width: 900px;
  margin: 0em auto 0;
  text-align: center;
  max-height:800px;  
  overflow: hidden;
}
  
.title_and_buttons { /*Ausrichtung aller Buttons und der h1*/
  max-width: 900px;
  text-align: center;
  margin: 1em auto; 
  padding:1px;
}
   
h1 {
  color: white;
  font-size: 1.7rem;
}

Im Body ist die Animation des ineinanderfließenden Hintergrundes zu sehen. Die keyframes bringen diese Animation zum Laufen. Zunächst muss man drei Farben definieren, die man in dem Übergang haben möchte. Des Weiteren war es wichtig die Dauer und Länge zu definieren. In diesem Fall sollte der gesamte Übergang 13 Sekunden dauern und unbegrenzt durchlaufen.

body {
  font-family: "Comic sans MS"; 
  background-size: cover; 
  justify-content:center;
  background-position: center;
  background: -webkit-linear-gradient(132deg, #FC415A, #591BC5, #4a8ead); 
  background-size: 400% 400%;
  align-items: center;
  min-height: 100%;
  overflow:hidden;
  -webkit-animation: moving_background 13s ease infinite;
  animation: moving_background 13s ease infinite;
}

@-webkit-keyframes moving_background {  /*Animation des Backgrounds, der in Dauerschleife die Farben wechselt*/
  0% {
      background-position: 0% 50%;
  }
  50% {
      background-position: 100% 50%; /*Inspired by https://www.sliderrevolution.com/resources/css-animated-background/*/
  }
  100% {
      background-position: 0% 50%;
  }
}

Die Buttons

Die Buttons haben wie schon zuvor erwähnt den funktionalen Zweck den User durch die Szenen zu geleiten und verschiedene Animationen hervorzurufen. Somit sind diese essenziel für das Abspielen der Animation. Aus diesem Grund werden diese oberhalb der Animationsbox dargestellt, damit die Aufmerksamkeit des Users zu den bestimmten Zeitpunkten darauf gelenkt wird.

Die Buttons haben alle den selben Stil, jedoch haben alle verschiedene Dauer und Art und Weise der Animation. Daher wurde jeder einzelne Button in CSS3 angelegt. Das Aussehen der Buttons ist Oval und hat drei Farbverläufe, das in zarten und hellen Farben gehalten ist, um mit dem Hintergrund zu harmonieren. Beim Hovern erfolgt ein Spiegeleffekt bei dem die Farben von rechts nach links ineinander laufen. Durch das bewegte Gelb wir ein Relief- bzw. Spiegeleffekt erzeugt. Die transition ermöglicht dies.

#button_aufwecken { /*Design und Animation der Buttons. Alle haben die gleiche Einstellung nur andere Animationsangaben. Daher jeden Button einzeln angelegt, anstatt die zusammenzufassen*/
  border-radius: 50%;
  align-items: center;
  font-size: 15px;
  display: flex;
  margin: auto;
  background-image: linear-gradient(135deg, #ee9ca7 0%, #fbed96 51%, #ee9ca7 100%);  /*Inspired by https://blog.avada.io/css/button-hover-effects/*/
  background-size: 200% auto;
  box-shadow: #a05a9c 0px 0px 5px;
  -webkit-animation: push_buttom 3s infinite;
  animation: push_button 3s infinite;
  outline: none;
}


@-webkit-keyframes push_button {                       /*Inspired by https://css-tricks.com/css-animation-libraries/*/
  0% {
    box-shadow: 0px 0px 4px rgb(255,250,250);
  }
          
  
  50% {
    box-shadow: 0px 0px 23px rgb(255,250,250);
  
  }
  100% {
    box-shadow: 0px 0px 12px rgb(255,250,250);
  }
}

@keyframes push_button {                       
0% {
  box-shadow: 0px 0px 4px rgb(255,250,250);
}
        

50% {
  box-shadow: 0px 0px 23px rgb(255,250,250);

}
100% {
  box-shadow: 0px 0px 12px rgb(255,250,250);
 }
} 

#button_aufwecken:hover {
  background-position: right center;
  transition: all 0.5s ease-out;
  }
      
.button_1{
  flex: 1 auto;
  margin:5px;
  padding:10px 25px;
  text-align:center;
  transition: all 0.5s ease-out;
  cursor:pointer;
  background-size: 200% auto;
  font-family: "Comic sans MS";
}

Animierte Objekte

Alle benutzen Bilder, bis auf die Hintergrundbilder der Szenen, haben einen funktionalen Zweck. Alle Bilder sind PNG Dateien und von Pixabay. Durch die position: relativ war es einfach alle Objekte in einer Szene zu platzieren. Ausgerichtet und an den gewünschten Platz gebracht wurde mit bottom, top, left, right und margin.  Keyframes erzeugen die Animationen der Objekte. Die nachfolgenden Abschnitte beschreiben die einzelnen animierten Objekte.

Text in Sprechblase

Der sprechende Text, den Bobby in der Sprechblase sagt zoomt rein und raus und wechselt dabei zwischen drei Farben. So sollte die Aufmerksamkeit auf den Text gelenkt werden, damit der User den Anweisungen folgen kann. Dazu wird die animation-timing-function auf ease gesetzt. Zudem soll der Zoomeffekt in Dauerschleife ablaufen. Daher der Wert infinite. Durch scale() konnte die Größe der Transformation des Textes eingerichtet werden. Color sorgt für den Farbverlauf, der sich über die verschiedenen Sequenzen (0%, 50%, 100%) ändert.

#welcome_text { /*Annimation für Text in der Sprechblase. Wird in jeder Szene eingesetzt*/
  position: relative;
  bottom: 392px;
  left: 475px;
  z-index: 4;
  font-size: 10px;
  box-sizing: border-box;  
  overflow: hidden;
  border-width: 20px;
  border: 1px hidden;
  width: 135px;

  -webkit-animation: typing_hello 1.5s ease infinite; 
  -webkit-animation-delay: 0s;
  -webkit-animation-play-state: paused;
  -webkit-animation-fill-mode: forwards;

  animation: typing_hello 1.5s ease infinite;
  animation-delay: 0s;
  animation-fill-mode: forwards;
  animation-play-state: paused;     
}

  @-webkit-keyframes typing_hello {
   0% {
    transform: 
       scale(0.7, 0.7);
       color:rgb(116, 9, 107)
  }
   50% {
    transform: 
       scale(0.9, 0.9);
       color:rgb(85, 25, 134)
  }
   100% {
    transform: 
      scale(0.7, 0.7);
      color:rgb(73, 41, 214)
  }
}

Fliegender Hot Dog

Für die Animation des fliegenden Hot Dogs wurden in den keyframes die Werte translateX(), translateY() und rotate() verwendet. Die beiden ersten Werte sorgen für die Verschiebung auf der X- und Y-Aschse, wobei ein negativer translateY() Wert das Objekt nach oben versetzt. Daher ist bei 50%, das der höchste Punkt der Flugbahn sein soll, ein negativer Wert von -80px. rotate() sorgt für die Rotation des Objektes. Hierbei müssen Gradzahlen eingetragen werden.

#hot_dog { /*Animation des fliegenden Hot-Dogs*/
  width: 47px;
  z-index: 2;
  position: relative;
  bottom: 300px;
  right: 225px;

  -webkit-animation-name: flying_hot_dog;
  -webkit-animation-duration: 2s;
  -webkit-animation-timing-function: linear;
  -webkit-animation-fill-mode: forwards;
  -webkit-animation-delay: 0s;
  -webkit-animation-iteration-count: 1;
  -webkit-animation-play-state: paused;
  
  animation-name: flying_hot_dog; 
  animation-duration: 2s;
  animation-fill-mode:forwards;
  animation-delay: 0s;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-play-state: paused;
}
 
  @-webkit-keyframes flying_hot_dog {
    from  { transform: translateX(0px) translateY(20px)  rotate(0deg) }
    50%   { transform: translateX(220px) translateY(-80px) rotate(180deg) }
    to    { transform: translateX(440px) translateY(95px)rotate(360deg) }
  }

  @keyframes flying_hot_dog {
    from  { transform: translateX(0px) translateY(20px)  rotate(0deg) }
    50%   { transform: translateX(220px) translateY(-80px) rotate(180deg) }
    to    { transform: translateX(440px) translateY(95px)rotate(360deg) }
  }

Bello und Bobby beim Ballspielen

Die Animation der zwei spielenden Hunde war am schwierigsten zu gestalten, da hier der Zeitfaktor eine große Rolle spielt, damit alles synchron abläuft. Zunächst die Gestaltung der beiden springenden Hunde. Hierbei muss man die Sequenzen (0%-100%) der bottom-Wert ändern. Je größer der Wert, desto höher steigen die Objekte auf. Die ease-out Eigenschaft sorgt dafür, dass das Ende der Sequenz langsamer abläuft. So kommt der fließende Sprung zustande. Beide Hunde haben die selben Animationseigenschaften. Der Unterschied liegt im animation-delay. Bello fängt eine Sekunde später an zu springen als Bobby. So entsteht der abwechselnde Sprung.

#bello { /*Ab hier folgt die Animation der zwei mit dem Ball spielenden Hunde*/
  width: 90px;
  z-index: 3;
  position: relative;
  bottom: 430px;

  -webkit-animation: move_bello 2s infinite;
  -webkit-animation-delay: 1s;

  animation: move_bello 2s infinite;
  animation-delay: 1s;
}

@-webkit-keyframes move_bello {
  from { bottom: 477px; animation-timing-function: ease-out; }
  50% { bottom: 570px; animation-timing-function: ease-out; }
   to { bottom: 477px; }
}

@keyframes move_bello {
  from { bottom: 477px; animation-timing-function: ease-out; }
  50% { bottom: 570px; animation-timing-function: ease-out; }
   to { bottom: 477px; }
}

#bobby {
  width: 90px;
  z-index: 3;
  position: relative;
  left: 200px;
  bottom: 430px;

  -webkit-animation: move_bobby 2s infinite;
  animation: move_bobby 2s infinite;;
}

@-webkit-keyframes move_bobby {
  from {  bottom: 477px; animation-timing-function: ease-out; }
    50% { bottom: 570px; animation-timing-function: ease-out; }
     to { bottom: 477px; }
}

Die Animation des Balls wurde nach dem selben Konzept wie die des Hot Dogs gestaltet. Hier bestand die Schwierigkeit mit der Positionierung und der Dauer des fliegenden Balls. Es musste alles auf die beiden springenden Hunde angepasst werden, sodass der Effekt eines Kopfballs entsteht.

Saltomachender Bobby

In der letzten Szene macht Bobby ein Rückwärtssalto. Dieser Effekt wurde mit den gleichen Eigenschaften wie bei dem fliegenden Hot Dog und Ball animiert. Da der Charakter sich auf einer Stelle bewegt und nur hochspringt und dreht, bleibt der translateX()vWert bei 0px. Dem entsprechend muss der translateY() und rotate() angepasst werden.

#night_dog {
  width: 80px;
  position: relative;
  right: 380px;
  bottom: 1039px;
  -webkit-animation: salto_dog 2s infinite;
  -webkit-animation-timing-function: linear;
  animation: salto_dog 2s infinite;
  animation-timing-function: linear;
}

@-webkit-keyframes salto_dog {  /*Animation von Bobby, der eine Rückwärtsrolle macht*/
  from  { transform: translateX(0px) translateY(0px)  rotate(0deg) }
  50%   { transform: translateX(0px) translateY(-80px) rotate(-180deg) }
  to    { transform: translateX(0px) translateY(0px)rotate(-360deg) }
}

Buttons

#button_reload {
border-radius: 50%;
align-items: center;
font-size: 15px;
display: flex;
margin: auto;
background-image: linear-gradient(135deg, #ee9ca7 0%, #fbed96 51%, #ee9ca7 100%); /*https://blog.avada.io/css/button-hover-effects/*/
background-size: 200% auto;
box-shadow: #a05a9c 0px 0px 5px; 
margin-top: -50px;
}

#button_reload {
-webkit-animation-name: button_load;
-webkit-animation-duration: 3s;
-webkit-animation-timing-function: linear;
-webkit-animation-fill-mode: forwards;
-webkit-animation-iteration-count: infinite;
-webkit-animation-play-state: paused;
-webkit-animation-direction: alternate-reverse;

animation-name: button_load; 
animation-duration: 3s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-iteration-count:infinite;
animation-play-state: paused;
animation-direction: alternate-reverse;
}

@-webkit-keyframes button_load {
  from  { transform: translateX(-20px) scaleX(1.0)}
  to    { transform: translateX(20px) scaleX(-1.0)}
} 
 

Die Buttons wurden im vorherigen Kapitel schon beschrieben. Nun wird näher auf die animierenden Effekte eingegangen. Der Effekt des Einblendens wurde durch die opacity Eigenschaft erzeugt, der von 0 auf 1 steigt und durch die animation-duration in die Länge gezogen wird. Der erste und letzte Button haben jedoch ein paar zusätzliche Effekte. Beim ersten Button „Aufwecken“ leuchtet der Button-Hintergrund in Weiß. Durch den versetzten box-shadow und der Dauerschleife (infinite) wird das pulsierende Leuchten erzeugt (siehe Bild ). Der letzte Button „Neustart“ dreht und bewegt sich von links nach rechts und rückwärtsrum, während sich dieser vertikal spiegelt. Die animation-direction: alternate-reverse gibt an, dass die Animation sich vor- und zurückspielen soll. Animation-timing-function sorgt für den linearen. also gleichbleibenden/flüssigen Ablauf. translateX() sorgt dafür, dass sich der Button von links nach rechts bewegt. scaleX() hingegen sorgt für die Spiegelung, wobei der negative Wert die Spiegelung an der X-Achse erzeugt.

Gute Nacht, Bobby Schrift

Der Abschließende Text „Gute Nacht, Bobby“ wurde mit einer Zoom-, Leucht- und Rotations-Funktion gestaltet. Wie schon zuvor erwähnt erzeugt scale() den Zoomeffekt. Für das Textleuchten ist text-shadow zuständig. rotate() sorgt für die Drehung des Textes. Der Unterschied bei dieser Textanimation liegt in der animation-timing-function. Hierbei setzt man cubic-bezier () ein um, einen Verzerrungseffekt zu erstellen.

#good_night_bobby{ /*Verabschiedung durch "Gute Nacht" Text Animation*/
  position: relative;
  bottom: 1500px;
  font-size: 30px;
  color: white;
  -webkit-animation: push_good_night 3s infinite;
  animation: push_good_night 3s infinite;
  animation-timing-function: cubic-bezier(.1,0,.7,1);
  outline: none;
}

  @-webkit-keyframes push_good_night {
   0% {
    transform: scale(1);
    text-shadow: 2px 3px 6px rgb(3, 246, 255);
  }
   20% {
    transform: scale(1.1) rotate(2deg);
  }                                                  
   40% {
    transform: scale(.97);
  }
   50% {
    text-shadow: 6px 6px 8px rgb(19, 236, 184);
 }
   60% {
    transform: scale(.99) rotate(-2deg);
 }
   80% {
    transform: scale(1.05);
 }
   100% {
    transform: scale(1);
    text-shadow: 2px 3px 6px rgb(135, 222, 241);
 }
 }

  @keyframes push_good_night {
   0% {
    transform: scale(1);
    text-shadow: 2px 3px 6px rgb(3, 246, 255);
  }
   20% {
   transform: scale(1.1) rotate(2deg);
  }                                                  
   40% {
   transform: scale(.97);
  }
   50% {
   text-shadow: 6px 6px 8px rgb(19, 236, 184);
}
   60% {
   transform: scale(.99) rotate(-2deg);
}
   80% {
   transform: scale(1.05);
}
   100% {
   transform: scale(1);
   text-shadow: 2px 3px 6px rgb(135, 222, 241);
}
}

JavaScript/jQuery

var name = "Snoopy" /*Variable für die Namensabfrage für die Begrüßung von Bobby*/

$(document).ready(function(){
/*Funktion, bei der bei einem Buttonklick bestimmte Objekte sichtbar oder ausgeblendet werden*/
$("#button_aufwecken").on("click", function() {  /*Button "Aufwecken"*/
    $(".story_start_scene").css({"visibility": "hidden"});
    $(".backgroundimage_livingroom").css({"visibility": "visible"}); 
    $("#hello_dog").css({"visibility": "visible"});
    $("#speak1").css({"visibility": "visible"});
    $("#button_park").css({"visibility": "visible"});
    $("#button_aufwecken").css({"visibility": "hidden"})
    $("#welcome_text").css({"visibility": "visible"});
    $("#name_text").css({"visibility": "visible"});
    $("form").css({"visibility": "visible"});
    
    $("#button_park").css({"-webkit-animation-play-state": "running"}); /*Animationen, die pausiert werden, werden hierbei zum Abspielen gebracht*/
    $("#welcome_text").css({"-webkit-animation-play-state": "running"});

    name = prompt("Bitte gib deinen Namen ein", "Snoopy");     /*Namensabfrage. Inspired by https://www.w3schools.com/jsref/met_win_prompt.asp*/
    console.log(name);

    if (name != null) {                                                                    
        document.getElementById("welcome_text").innerHTML =
        "Hallo " + name + "! Ich bin Bobby. Lass uns den Tag zusammen verbringen.";
      }

});
 

Um die Übergänge zwischen den einzelnen Szenen und Animationen möglich zu machen, wurde jQuery eingesetzt. Durch den Buttonklick werden Objekte, die in HTML5 auf „hidden“ gesetzt sind, sichtbar gemacht. Dafür nutzt man die $(“#button”).on(“click”, function() {}}); . Diese zeigt welche Objekte beim Buttonklick gezeigt werden und welche verschwinden sollen. Die Namensabfrage zwischen der ersten und der zweiten Szene erfolgte über JavaScript mit der promt() Methode.

Bobby JS
Bobby JS

Hierbei wurde eine Variable erstellt, das einen default Wert liefert, der in der promp() Abfrage und if-loop eingefügt ist. Es öffnet sich ein Pop-up Fenster bei dem die Aufforderung „Bitte gib deinen Namen ein“ und dem default Wert „Snoopy“ steht. Diese wurden zuvor definiert. Wenn der User seinen Namen eintippt, nimmt die p id=“welcome_text“ diesen entgegen und Bobby begrüßt den User mit „Hallo [Username]! Ich bin Bobby. Lass und den Tag zusammen verbringen“. Falls das Eingabefeld leer bleibt, begrüßt Bobby den User mit dem Namen null. Durch diese Funktion wird eine Bindung zum User aufgebaut.

Die Animationen, die mit Hilfe von transitions und keyframes in CSS3 erstellt wurden, wurden bei webkit-animation-play-state auf paused gesetzt. Der Grund dafür ist, dass bestimmte Funktionen wie animation-delay oder animation-duration ab der Start Szene anfangen zu zählen. Das war aber nicht die Intention. Es sollten alle Abläufe erst nach einem Buttonklick starten. So war das Problem z.B. bei dem zweiten Button „Lass und in den Park gehen“. Dieser wird nach 3 Sekunden eingeblendet. Wäre -webkit-animation-play-state auf running gesetzt, so hätte das Einblenden des Buttons nach 3 Sekunden nicht funktioniert, wenn man sich länger als 3 Sekunden in der Start Szene befunden hätte. Der Button wäre dann beim Szenenwechsel schon da und der Einblende Effekt wäre nicht sichtbar. Damit die einzelnen Animationen erst beim Buttonklick abspielen, muss man diese über jQuery bei -webkit-animation-play-state auf running setzen.

$("#hot_dog_text").css({"-webkit-animation-play-state": "running"});
$("#button_hot_dog").css({"-webkit-animation-play-state": "running"});

Besonderheiten

Eine Besonderheit ist die im Hintergrund eingesetzte Musik, um die Animation spannender zu gestalten und den User in eine angenehme Stimmung zu versetzen. Des Weiteren wurden so gut wie alle benutzen Objekte animiert. Es wurde versucht jedes Animationselement individuell zu gestalten, um verschiedene visuelle Effekte zu erzeugen. Die letzte Besonderheit ist, dass der letzte Button einen Neustart der Animation ermöglicht, falls man erneut das Story Telling durchspielen möchte.

Schwierigkeiten

Beim Erstellen der Animation traten zwei Probleme auf.

  1. Der animierte Sprechtext sollte ursprünglich abgetippt werden. Dafür wurde die step() Methode verwendet. Leider konnte ein Zeilenumbruch für die Animation nicht erstellt werden, da ansonsten der “abgetippte Text” nicht korrekt funktioniert hat wie er es sollte. Dieser hätte in die Sprechblase passen müssen. Daher wurde eine alternative Darstellung des Textes eingebaut.
  2. Die Hintergrundmusik wird manchmal in Google Chrome nicht abgespielt. Daher wird empfohlen sich die Animation in Microsoft Edge anzuschauen.

Dieser Beitrag ist im Studiengang Informationsmanagement an der Hochschule Hannover im Rahmen des Kurses Entwicklung von Multimediasystemen (Sommersemester 2021, Amy Linh Hoang,  Prof. Dr.-Ing. Steinberg) entstanden. Verwendete Techniken sind HTML5, CSS3 und JavaScript. Die besten Tutorials stellen wir Euch hier in den nächsten Wochen nach und nach vor.