Inkle's Ink: create buttons that are always on screen (eg. "Inventory")

I’ve very recently started learning Ink and I can’t seem to find information on whether you can create options that always exist on the screen, like “Inventory” or “Check Stats”. I know you can do this on Twine, for example, using a “footer” passage. Is there something similar on Ink?—Thanks!

Ink requires you to write your own html file. All ink itself cares about is the JSON that it spits out. The rendering of the json is done by either inkjs or the unity engine stuff. So what I’m saying is that any fancy stuff beyond just printing the main text is not covered by the basic html page that the editor spits out and will have to be covered by you.

To do what you want to do, I believe you need to access the variables through functions. You can find documentation on how to do it here.

As an added bonus, I took some notes when I was messing with ink on how to do this in JS (the docs are for C#).

Ink and JS interaction notes
// Important note:
//   All functions and variables must be already declared in
//   Ink before you can access them in javascript

Function binding
- https://github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md#external-functions

	ink declaration:
		EXTERNAL multiply(x,y)

	javascript:
		story.BindExternalFunction("multiply", function(arg1, arg2) {
			return arg1 * arg2;
		});

	example use in ink:
		3 times 4 is {multiply(3, 4)}.

Setting variables
- https://github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md#settinggetting-ink-variables

	ink declaration:
		VAR player_health = 50

	javascript:
		story.variablesState["player_health"] = 100;
		var health = story.variablesState["player_health"];

Lists
- https://github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md#working-with-lists

	ink declaration:
		LIST fruit = orange, apple, banana
		LIST shopping_list = default
		~ shopping_list = ()  // clear list

	javascript:
		var newList = new inkjs.InkList("fruit", story);
		newList.AddItem("apple");
		story.variablesState["shopping_list"] = newList;

Variable Observer (works with both LIST and VAR)
- https://github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md#variable-observers

	ink declaration:
		VAR health = 100

	observe variables in JS:
		story.ObserveVariable("health", function(varName, newValue) {
			SetHealthInUI(newValue);
		});
2 Likes

What you say kind of makes sense—kind of, because I’m not that good in JS and totaly ignorant of C#. But I get it, I need to edit the .js and .html files myself, so that a variable or a button appears on some footer.

No idea how to do that, but I’ll dig into it if I need to get there.

(I’m not even doing the JSON export, I’ve been doing the Export for web... option, by the way.)

Yeah. “Export for web” exports the html file, ink.js (the ink engine converted to JS. Don’t edit this), main.js (the script that is the middle man between the html page and ink.js and is what renders the output to your page), and story.js (your game script in json form).

Very important: Once you start editing stuff, be sure to only use the “export JSON” option or else it’ll overwrite the html and JS files with the defaults again. I’d hate for you to lose your work. Using the JSON option only updates story.js.

OK, I think I understand.

This is interesting. So you mean that “myStory.js” (created when choosing Export for web...) and “myStory.json” (created when choosing Export to JSON) is the same thing?

Comparing the two files (of the default story) gives me:

myStory.js:
var storyContent = {"inkVersion":19,"root":[["^Once upon a time...","\n",["ev",{"^->":"0.2.$r1"},{"temp=":"$r"},...

myStory.json:
{"inkVersion":20,"root":[["^Once upon a time...","\n",["ev",{"^->":"0.2.$r1"},{"temp=":"$r"},...

… so basically the difference is just the beginning?
Say myStory.js is var storyContent = myStory.json ? :grinning_face_with_smiling_eyes:

Therefore, I need to fix the main.js so that it creates all the buttons and extra menus I need? Like showing variables etc.

Oh right. Man, it’s been a while since I used ink. But yeah, the difference is that myStory.js assigns the JSON to a variable so that the engine can use the data. Otherwise they’re identical.

I don’t know if you’re a windows users, but I actually wrote a windows powershell script that automatically recompiles your ink file into a JS file that has the JSON with the variable assignment slapped on there (just like myStory.js, that is). It watches your ink files for changes, so all you have to do is save in the editor (using control+S, not export) and it’ll compile.

You’ll need to have this file and also inklecate.exe in the same directory as your myStory.js file and ink files for it to work. Ink provides the inklecate file in their releases.

Power Shell script
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    Set-Location $PSScriptRoot
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "./"
    $watcher.Filter = "*.ink"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true  

### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
    $action = { $path = $Event.SourceEventArgs.FullPath
                Invoke-Expression "./inklecate.exe -o myStory.js story.ink"
                @("var storyContent = ") +  (Get-Content ".\myStory.js") | Set-Content ".\myStory.js"
              }

### DECIDE WHICH EVENTS SHOULD BE WATCHED 
    Register-ObjectEvent $watcher "Created" -Action $action
    Register-ObjectEvent $watcher "Changed" -Action $action
    Register-ObjectEvent $watcher "Deleted" -Action $action
    Register-ObjectEvent $watcher "Renamed" -Action $action
    while ($true) {sleep 5}

I got sidetracked. Oops.

You’ll probably want to add the buttons to the html file itself. To display the inventory or stats, I’d have the buttons either display a hidden div over the input, or have its output added directly to the text output. I wouldn’t use ink to do it. I’d also probably avoid altering main.js and either add your JS functions to the html file or create an additional JS file to include after main.js, but that’s just a matter of preference.

To access the data you need for the inventory or stat functions, you should be able access it using story.variablesState["ink_variable_name"] like in my notes.

Because of how ink works, I’m concerned that if you made the links direct you to a portion of the ink script that outputs your inventory or something, you wouldn’t be able to get back to where you were in the story. That’s why I’d avoid using ink itself for these functions.

Most of this information is going completely off theory since I haven’t played with it enough to know for sure. So please don’t take it as gospel.

1 Like

No, it’s very useful!

(To start with, you’ve answered my question about whether ink has such a functionality implemented within itself—which it hasn’t.) :blush: So, at least I know I have to work with JS.

Thank you!

1 Like