Need help with educational CYOA (Sugarcube)

Hi everyone,

New Twine user here and I am using Sugarcube 2.28.2.

I work at a university as a course designer and I am helping a professor create a self-paced module that will teach users Middle English. It’s sort of like an educational CYOA built around the Chaucer Tales.

There are several moments where new vocabulary words are introduced in different passages.

What I am trying to figure out is

  1. How to chunk and organize passages as “chapters” in the leftside bar.

  2. if it is possible to create a sort of log for the user of all the vocabulary words they have come across thus far. It would sort of be like a dictionary of all the words/concepts they have encountered and hopefully it would take them back to the chapter in which the word or concept was introduced. Ideally it would be in the leftside sidebar. I know its possible to pick up items and sort of have them stored somewhere in the game, but I would like to do this with important words.

Please feel free to point me to the right documentation as I am still a bit new to this and I am having trouble asking the right question to find the information I need. Are there good examples of other Twine games that use a similar mechanic with chapters and captured words? Or maybe this isn’t even possible?

Thanks in advance!

There are many ways to accomplish what you’re looking for, but the right solution depends on a lot of things.

First of all, if you are using the default SugarCube interface (not using the special “StoryInterface” passage to create your own page layout), then in order to add Chapters to the sidebar, all you need is the special “StoryMenu” passage.

You can look in the SugarCube documentation for info on this, but basically you create a passage titled StoryMenu and fill it with links to passages you want to appear in the sidebar. You can do this easily with SugarCube’s link markup:


[[Chapter 1|Chapter 1 Passage]]
[[Chapter 2|Chapter 2 Passage]]
...

The documentation will explain more about this as well.

As for vocabulary words, there are several ways to accomplish this. Perhaps the most straight-forward way is to set up a comprehensive list of all words that will appear and in which chapter they will first appear. The best way to do this is in the Story JavaScript, making use of the pre-defined setup variable to store all of these words.


setup.vocab = {
	"gutenTag" : {
		"german" : "Guten Tag",
		"english" :"Good Day",
		"definition" : "A formal greeting used mainly between the hours of 10 AM and 5 PM.",
		"firstAppears" : "Chapter 1 Passage",
	},
	"guteNacht" : {
		"german" : "Gute Nacht",
		"english" : "Good Night",
		"definition" : "A farewell used at bedtime.",
		"firstAppears" : "Chapter 2 Passage",
	},
	...
};

So, as you can see here, each word has its own object containing the word/phrase, its English translation, an explanation of how it’s used, and the passage title where it first appears (for linking purposes).

Next, you want a passage using the special name StoryInit. Here, you’ll put things you want to set up the very first time the story is created. In here, you should create a variable to hold the list of discovered words:


<<set $LearnedWords = []>>

Now, inside the chapter when the word first appears, you could do this:

<<run $LearnedWords.pushUnique(setup.gutenTag)>>
<<run $LearnedWords.pushUnique(setup.guteNacht)>>

Using the StoryMenu passage I mentioned earlier, you can add a link to a “Dictionary” passage, in which you would have something like this:


<<for _id, _word range setup.vocab>>
		<h3>_word.german -- _word.english</h3>
		<p> _word.definition </p>
		[[Go to Chapter|_word.firstApears]]
<</for>>

As I’ve said, this is just one of many methods, and a bit of a clunky one at that, but it should give you somewhat of an idea how to start handling things. I highly recommend looking through the SugarCube documentation and playing around with things to get a better feel on how they work. That’s really the best way to learn this engine. It will also help you come up with more specific questions.

Oh, and if you wanted the wrds themselves to appear in the sidebar, this is possible but much more involved. It will either require drawing them in using JavaScript or doing what I meantioned above and using the StoryInterface Passage to create your own page layout. (And it still might require some JavaScript).

I hope this helps give you a little direction. Feel free to ask more specific questions here or in the future when you have a better handle on SugarCube.

EDIT: Sorry, I had to fix my method. I replied to this before I’d had coffee and did it in a way that wouldn’t actually work.

1 Like

I have a correction to make in regards to the Story Menu passage. I had a bit of a miconception of how it works, as I don’t use it. You can actually populate it using a loop. So, if you want all the learned words to appear in a long list in the sidebar, you can put a <<for>>> loop in the Story Menu passage similar to the one displayed above, but only using it to display links.

The naming of the special passages (and special passage tags) needs to be exactly the same as shown in the documentation, the letter-casing needs to be correct and you can’t add space characters between the individual “words” that make up a specific name.

So the two special passages mentioned within your explanation need to be StoryInterface and StoryMenu respectively.

Yes, sorry. I was trying to be helpful, but I think I rushed myself a bit too much and made several obvious mistakes.

You were being helpful, and don’t worry about making mistakes as we all do that at times. :smile:

I’m not sure if you’re aware that you can use the “edit this post” feature, found the toolbar that appears after each posted comment, to edit the contents of any post you make. You may want to make use of this functionality to revise/correct your explanation, in case any future reader of it doesn’t read any of the later replies associated with it.

Yes, I’ve edited it several times. Just fixed the passage names. (I think)

Hi Tilea,

Thank you SO much for this; this is extemely helpful.

I did exactly as you said and this is a great start for me to get deeper into Twine/Sugarcube. I know I’ll be able to phrase questions better soon but I am having trouble with the following:

  1. With the following code to add a word to the Dictionary passage
<for _id, _word range setup.vocab>>
		<h3>_word.german -- _word.english</h3>
		<p> _word.definition </p>
		[[Go to Chapter|_word.firstAppears]]
<</for>>

it creates a new Passage called “_word.firstAppears”. Is this supposed to happen?

  1. All the words are displaying in the Dictionary when I start the game, even though I haven’t progressed through to a certain passage where I would “pick up” the vocabulary word.

  2. I love having the chapters in the sidebar using the StoryMenu passage, but currently I have Chapter 1, for example, composed of 8 separate passages. Is it possible to have all 8 passages be contained under Chapter 1?

Thank you!

Unfortunately the “auto create missing (referenced) passages” feature only understands the standard formats of Wiki based links. eg.

[[Link Text same as Target Passage Name]]
[[Link Text|Target Passage Name]]
[[Link Text->Target Passage Name]]
[[Target Passage Name<-Link Text]]
etc...

…so it thinks the _word.firstAppears variable reference is actually the textual name of the Target Passage, and this is why it creates the unwanted Passage. In that specific instance I suggest you use the (link:) macro instead, because that is ignored by the above feature.
(untested example)

<for _id, _word range setup.vocab>>
		<h3>_word.german -- _word.english</h3>
		<p> _word.definition </p>
		<<link "Go to Chapter" _word.firstAppears>>
<</for>>

Yes, so, I’m embarrassed to admit that I made many mistakes when explaining this and did not catch them all.

First of all, when you add a new word in a chapter, you will need to add the word’s ID as you put it in the setup object in your JavaScript. So, instead of this:

<<run $LearnedWords.pushUnique(setup.gutenTag)>>

You will want this:

<<run $LearnedWords.pushUnique("gutenTag")>>

You also might want to put all of these add statements inside of an <<if>> statement to check whether the user has visited this chapter before. There is a built-in visited() function to test whether the passage appears in the story history, but the longer the application is used, the less reliable that becomes. Because pushUnique() is being used, it isn’t strictly necessary to have this test, but it prevents unnecessary code execution.

So, a very simple way to do this without creating any new variables would be to test for the existence of a word in the $LearnedWords array to determine whether that word and the others that would be acquired in that chapter already exist:

<<if !($LearnedWords.includes("gutenTag"))>>
	<<run $LearnedWords.pushUnique("gutenTag")>>
	...
<</if>>

With this code in place, the application will only attempt to add the words if one of them – whichever you choose --does not already exist in the list.

So, onto drawing the dictionary itself.

<<for _index, _wordId range $LearnedWords>>
	<<set _word = setup.Words[_wordId]>>
	<h3>_word.german -- _word.english</h3>
	<p>_word.definition</p>
	<<link "Go to Chapter" _word.firstAppears>>
	<</link>>
<</for>>

Note: I used the basic SugarCube macro syntax to create a link here. I expect Greyelf’s example will also work, but if you’re relying on the SugarCube documentation, this syntax will be what you learn.

Changing these things will fix two of your problems (I hope). As to the chapters in the sidebar, I’m not aware of a way to use the StoryMenu passage to create an expanding list. (I believe this is what you’re asking for: like a tree that expands and collapses). For this, I believe you will have to use JavaScript to add a block of links to the sidebar beneath each Chapter link and show or hide it when the user clicks the main chapter heading.

If you aren’t familiar with how to do this, just let me know and I’ll write up an example. I hope I’ve clarified and fixed my errors from before.

Hi Tilea,

Thanks for your help again. I have tried your clarifications and am getting the following error in the Dictionary (the example below is the word “accent” that I used FYI):

Error: <>: bad evaluation: Cannot read property ‘accent’ of undefined

<<set _word = setup.Words[_wordId]>>

_word.impterm

_word.definition

Go to Chapter

Where exactly would I put the if statement you provided? I am assuming it should go in the passage with the <<run $LearnedWords.pushUnique("gutenTag")>>

Also, I am not familiar with how to add a block of links to the sidebar beneath each Chapter link and show or hide it when the user clicks the main chapter heading. So if you could provide an example whenever you have time, that would be great.

I have been going through all the SugarCube documentation and things are starting to make more sense and I am sure I will get there soon throughout the creation of this project.

Thanks again!

Actually, it won’t! :sigh:
I mistakenly left off the closing <</link>> tag, but I did mark that code as “untested”… :smile:

(and this forum’s software won’t let me go back and correct my mistake! :sigh:)

Okay, hang tight. I’m going to create a working example for you. Everything you want to do is hard to explain in a post if you aren’t familiar with coding (specifically web coding). And, it will let me make sure what I’m telling you will actually fit together correctly. It just might take me some time, so know that help is in-coming.

LanguageLearningExample.zip (138.8 KB)
Here you are. Import this into Twine and take a look around. I tried to offer explanations of what I’m doing in comments, but let me know if you need anything further explained.

Notes:

  1. I’m blind, so I apologize if things aren’t “lined up” intuitively. I do my best to at least make my code readable, but I’m sure the passage blocks in Twine are all over the place.
  2. In order to manipulate the elements on the page, I’m using the built-in jQuery library. So, if you’re looking up JavaScript tutorials on how to effect page content, you might see a different syntax. I find jQuery to be much more efficient and easy to work with, but your experience may vary.