~nromdotcom/gemif

ref: 914458c58f6158ecb8e30fdfc595e50df9e5eaba gemif/stories/src/tutorial/01-basics.gemif -rw-r--r-- 8.9 KiB
914458c5Norm MacLennan Update to fully-qualified module path to enable go get-ing 1 year, 1 month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
---
# the_basics The Basics

Welcome to GemIF! Gemini's Interactive Fiction engine.

In this tutorial, we'll walk through writing your own stories using the .gemif file format. While stories can technically be written directly in the "compiled" YAML format, gemif format provides a much more user-friendly experience and allows authors to write without worrying about a lot of semantic whitespace.

=> get_started Cool, let's get started!
=> simple_demo {~seen_demo} Carry on with the tutorial

---
# get_started The Basics pt 2

A GemIF story is made up of `Scenes` that you moved between through the use of `Transitions`.

## Scenes

Scenes are where the action happens. Each scene has the following attributes:

* ID: A scene's ID is its unique identifier within the story. The ID is used in Transitions to move the user from scene to scene.
* Name: A scene's Name is a user-friendly identifier for the page. It is displayed at the top of the page. This scene's Name is `The Basics pt 2`.
* Description: A scene's description is free-text describing what's happening in the scene. A description can optionally be rendered as a Golang `text/template`, which can be used along with advanced GemIF features to provide dynamic story-telling.
* Transitions: Each scene has 0 or more transitions. These transitions are represented as reader choices and move the user to the next scene. Not all scenes need transitions, but these are "terminal" state of the story.

A scene can, of course, be as many lines as you want and you can use Gemini text formatting freely.

## Transitions

A transition's job is to move the reader from one scene to another. A transition can also point back at its own scene, using advanced features to change the content.

Each transition has the following attributes:

* Destination: A transition's destination must be the ID of the scene the reader should move to.
* Description: A transition's description is the text presented to the reader for the given choice.
* Condition Options: Conditions are an advanced feature of GemIF that we'll cover in detail later. Suffice it to say, transitions can add or remove conditions from the reader's game which can be used to build dynamic stories.

Each transition must exist on a single line (that is, descriptions must not have newline characters).

=> simple_demo What do scenes and transitions look like?

---
# simple_demo The Basics pt 3

So now that you're somewhat familiar with the building blocks of a story - scenes and transitions - we can discuss what they actually look like.

## GemIF Format

Stories are best and most easily written in GemIF format. This is a plaintext format that looks a lot like Gemini format.

Each story is made up of one or more `.gemif` file with whatever names you want. And each file can contain or more scene (with associated transitions).

### Scenes
Let's look back at the first page of this tutorial for a simple example. The "source" of that scene looks like:

```
  ---
  # the_basics The Basics

  Welcome to GemIF! Gemini's Interactive Fiction engine.

  In this tutorial, we'll walk through writing your own stories using the .gemif
  file format. While stories can technically be written directly in the "compiled"
  YAML format, gemif format provides a much more user-friendly experience and allows 
  authors to write without worrying about a lot of semantic whitespace.

  => get_started Cool, let's get started!
```

Each scene must start with a triple-dash (`---`). Within files, the triple-dash is used as a scene separator.

The first line of a scene contains the scene's ID and Name, prefixed with an `#`.

```
  # <SceneID> <SceneName>
```

### Transitions
The other piece of special syntax in a scene are the transitions. Transitions look a lot like Gemini links, but have a few advanced features we'll talk about later.

```
  => <DestinationID> <TransitionDescription>
```

And that's basically all there is to it (we'll get into advanced features shortly).

=> the_basics {+seen_demo} If you want to see the first page again for reference, choose this.
=> story_metadata Or continue on...

---
# story_metadata The Basics pt 4

One last thing before we carry on to advanced features.

## Story Metadata
In addition to the .gemif files, GemIF stories require a single file named `metadata.yml`. This file contains basic information (well, metadata) about the story for GemIF to display to the reader.

The format is pretty simple and self-explanatory, but for completeness, your `metadata.yml` must contain:

* id: a server-unique id of your story
* name: a user-friendly name of your story
* description: a brief description of what you're story is about
* author: name or other identifier of the story author.

Here's the `metadata.yml` of this story, for reference.

```
  ---
  id: sample_story
  name: Sample Story
  description: A sort of hello world
  author: Norm MacLennan
```

=> conditions Alright, I get it, I get it. Bring on the advanced features!

---
# conditions Advanced Features pt 1

Now you know the basics of creating stories. You should be able to use these basics to create plenty of linear or branching narratives. But what if you need just a _little_ more power?

## Conditions
Conditions are "tags" that can be attached to the reader's game to denote that they have made (or not made) a particular choice.

Conditions can be attached or removed from game state through transitions. You can also use conditions to decide whether or not to present a given transition to a user.

### With Transitions
Conditions work with transitions through the use of condition directives on the transition itself. These directives are placed between curly-braces in between the destination and description.

It looks like this:

```
  => <destination> {<condition directives>} <description>
```

Did you notice in the previous scene, that if you moved back to the first scene you could suddenly jump right back to where you were? That was done with transitions.

On the GemIF demo scene, the transition back to the intro scene looks like:

```
  => the_basics {+seen_demo} If you want to see the first page again for reference, choose this.
```

That little `{+seen_demo}` attaches the `seen_demo` condition to the game state.

Then, back in the first scene there is a conditionally-hidden transition that didn't show up until you had that condition:

```
  => simple_demo {~seen_demo} Carry on with the tutorial
```

`{~seen_demo}` will only show the transition option if the reader's state has the `seen_demo` condition.

There are a handful of condition directives you can use, and you can provide as many as you like for each transition, separated with a space.

* `+condition`: adds `condition` to the user's state
* `-condition`: removes `condition` from the user's state
* `~condition`: only presents the transition to the user when they have `condition`
* `!condition`: only presents the transition to the user when they DON'T have `condition`

=> template What else can I do with conditions?

---
# template Advanced Features pt 2

In the previous scene, you learned how to use conditions to track information about the story state and conrol which choices the reader is presented with.

## Templates

You can also use conditions to conditionally render different parts of room templates. Scene descriptions are rendered as Golang `text/template`s. 

Templates have a `.Conditions` list in scope and some utility functions available.

If you returned to the first scene previously and gained the `seen_demo` condition, you should see `[seen_demo]` printed below, otherwise you may just see `[]:

{{.Conditions}}

That was produced with the token {{"`{{.Conditions}}`"}}.

A utility function, `ConditionMet` is in-scope to check if a reader has met a condition. Below you should see `true` or `false` based on whether or not you have the condition:

{{.ConditionMet "seen_demo"}}

This was produced with the token `{{"{{.ConditionMet \"seen_demo\"}}"}}`.

You can check the Golang text/template documentation for ways you can use templates to write if statements and other advanced conditional rendering.

=> whats_next Cool, well what's next?

---

# whats_next Compiling Your Story

Once you've written your story (or probably more like as you write your story), you can use `gemifc` to compile your story to YAML format for use by the `gemif` server.

```
$ gemifc [input directory] [output directory]
```

So to compile this story:

```
$ gemifc ./stories/src/tutorial ./stories/compiled
Compiling story ./stories/src/tutorial to ./stories/compiled/

Finished loading story:
  Name: Writing Tutorial
  Author: Norm MacLennan
  Descriptions: Documentation on writing GemIF stories
  Number of Rooms: 7

Serializing and writing to disk...
Done!
```

If you want to publish your story, just drop it in the configured stories directory of your GemIF server. If you don't want to run it yourself, feel free to email it to the GemIF mailing list at `~nromdotcom/gemif@lists.sr.ht` and I'd almost certainly be happy to host it for you.

THE END