The Bisquixe interpreter for Inform 7 and Inform 10 styling (new:full sound, internal links)

I’m releasing the first version of my Bisquixe interpreter and Simple Multimedia Effects extension.

Both can be downloaded here on github:

The interpreter goes in a folder called Templates in your inform directory, while the extension can be installed using the Inform IDE’s ‘install an extension’ button.

A sample game using Inform to model Twine can be found here:

Screenshot:

A sample game that has the appearance of text messages can be found here:

image

These games were created using Inform 7 code only. No editing of other files is required. If you see it flicker when you load, that’s because it’s executing css during run time. That can be fixed by simply editing the css ahead of time, but I wanted to show what you could do with just Inform.

This is the full code for the fake twine game:

Summary
"FakeTwine" by Mathbrush

Release along with a "Bisquixe" interpreter.

Include Simple Multimedia Effects by Mathbrush.
Include Basic Screen Effects by Emily Short.

Current Room is a room.

When play begins:
	css-set-fast ".BufferWindow;background-color;black";
	css-set-fast ".BufferWindow;padding;100px 250px 6px 2px";
	css-set-fast ".BufferWindow;overflow;auto";
	css-set-fast ".GridWindow;background-color;black";
	css-set-fast ".BufferLine;font-size;16px";
	css-set-fast ".BufferLine;color;white";
	css-set-fast ".Input;display;none";
	css-set-fast ".coverimage;display;none";
	css-set-fast ".interpretercredit;display;none";
	css-set-fast ".links;display;none";
	css-set-fast ".play;background-color;black";
	css-set-fast ".BufferLine;font-family;Verdana, sans serif";
	now the command prompt is "";
	
Report looking for the first time:
	[If we used when play begins, the first passage would be lower down.]
	clear the screen;
	say "Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the [passage world]."
	
To say passage (nextPassage - a passage):
	hyperlink "[nextPassage]" as "zzxvm [nextPassage]"

Passaging is an action applying to one thing.  Understand "zzxvm [any passage]" as passaging.

A passage is a kind of thing.

Carry out passaging:
	if the noun is a passage listed in the Table of All Passages:
		clear the screen;
		say "[reply entry]";
	
Some passages are defined by the table of all passages.

A passage has some text called the reply.

When play begins:
	now every passage is held by the player;

Table of All Passages 
passage	reply
world	 "'All the world's a [passage stage], and all the men and women are merely [passage players].'"
players	 "Don't hate the players, hate the game. -[passage Moby Dick]"
stage	 "At this stage, we're pretty similar to Twine. -[passage Moby Dick]"
moby dick	"Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the [passage world]."

Rule for printing the banner text:
	do nothing;
	
The room description heading rule does nothing.

Rule for constructing the status line:
	do nothing;

This is the full code for the text message game (with styling borrowed from @malacostraca’s Closure):

Summary
"TextMessaging" by Mathbrush

Release along with a "Bisquixe" interpreter.
Release along with a "Bisquixe" website.

Include Simple Multimedia Effects by Mathbrush.

Current Room is a room.

The room description heading rule does nothing.

Rule for constructing the status line:
	do nothing;
	
When play begins:
	css-set-fast ".BufferWindow;padding;100px 250px 6px 2px";
	css-set-fast ".GridWindow;background-color;white";
	css-set-fast ".coverimage;display;none";
	css-set-fast ".interpretercredit;display;none";
	css-set-fast ".links;display;none";
	css-set-fast ".Style_text;font-family; sans-serif";
	css-set-fast ".Style_text;border-radius; 20px 20px 20px 20px";
	css-set-fast ".Style_text;margin; 0 15px 10px";
	css-set-fast ".Style_text;padding; 15px 20px";
	css-set-fast ".Style_text;position; relative";
	css-set-fast ".Style_text;display; block";
	css-set-fast ".Style_text;width; 400px";
	css-set-fast ".Style_text;animation-name; popin";
	css-set-fast ".Style_text;animation-duration; 0.2s";
	css-set-fast ".Style_text;background-color; #E5E4E9";
	css-set-fast ".Style_text;color; #363636";
	css-set-fast ".Style_text:before; transform; rotateY(180deg)";
	css-set-fast ".Style_text:before;  border-color; #E5E4E9";
	css-set-fast ".Style_text:before;  left; -50px";
 	css-set-fast ".Style_text:before; border-color; #E5E4E9";
 	css-set-fast ".Style_text:before; border-radius; 50% 50% 50% 50%";
 	css-set-fast ".Style_text:before; border-style; solid";
 	css-set-fast ".Style_text:before; border-width; 0 20px";
 	css-set-fast ".Style_text:before; bottom; 0";
 	css-set-fast ".Style_text:before; clip; rect(20px, 35px, 42px, 0px)";
 	css-set-fast ".Style_text:before; content; ' '";
 	css-set-fast ".Style_text:before; height; 40px";
 	css-set-fast ".Style_text:before; position; absolute";
  	css-set-fast ".Style_text:before;right; -50px";
 	css-set-fast ".Style_text:before; width; 30px";
	[Now for your input]
	css-set-fast ".Style_input;font-family; sans-serif";
	css-set-fast ".Style_input;border-radius; 20px 20px 20px 20px";
	css-set-fast ".Style_input;margin; 0 15px 10px";
	css-set-fast ".Style_input;padding; 15px 20px";
	css-set-fast ".Style_input;position; relative";
	css-set-fast ".Style_input;display; block";
	css-set-fast ".Style_input;width; 400px";
	css-set-fast ".Style_input;animation-name; popin";
	css-set-fast ".Style_input;animation-duration; 0.2s";
	css-set-fast ".Style_input;background-color; #2095FE";
	css-set-fast ".Style_input;color; #363636";
	css-set-fast ".Style_input:before; transform; rotateY(0deg)";
	css-set-fast ".Style_input:before;  border-color; #2095FE";
	css-set-fast ".Style_input:before;  left; 420px";
 	css-set-fast ".Style_input:before; border-color; #2095FE";
 	css-set-fast ".Style_input:before; border-radius; 50% 50% 50% 50%";
 	css-set-fast ".Style_input:before; border-style; solid";
 	css-set-fast ".Style_input:before; border-width; 0 20px";
 	css-set-fast ".Style_input:before; bottom; 0";
 	css-set-fast ".Style_input:before; clip; rect(20px, 35px, 42px, 0px)";
 	css-set-fast ".Style_input:before; content; ' '";
 	css-set-fast ".Style_input:before; height; 40px";
 	css-set-fast ".Style_input:before; position; absolute";
  	css-set-fast ".Style_input:before;right; 420px";
 	css-set-fast ".Style_input:before; width; 30px";
 	css-set-fast ".Buffer_input; text-align; right";
	now the command prompt is " ";
	css-set-fast ".LineInput;border-radius; 20px 20px 20px 20px";
	css-set-fast ".LineInput;color; #363636";
	css-set-fast ".LineInput;margin; 0 15px 10px";
	css-set-fast ".LineInput;padding; 15px 20px";
	css-set-fast ".LineInput;position; relative";
	css-set-fast ".LineInput;display; block";
	css-set-fast ".LineInput;width; 400px";

To say text-style:
	set-any-class "text";
	
Before issuing the response text of a response: say text-style. 

Before doing something:
	say text-style;

The description of Current Room is "[text-style]You look around.[roman type]"

They work offline, too!

I’d like to add more features in the future. Since many uses of this game omit the quixe link, I’d like to add a Quixe thanks in the default banner text. I haven’t messed around with graphics or sound, since both involve a little bit of editing of the html files themselves, and I’m keeping this simple.

I’d love feedback, and would be interested in improving this.

31 Likes

Documentation:

Adding classes and CSS styling

set-any-class "your_class_name_here" allows you to give passages any ‘style’ you want. It behaves just like say italic type, and is turned off with say roman type like usual.

It adds a class called Style_your_class_name_here to each span and Buffer_your_class_name_here to each div that contains text of this style.

css-set-fast "element_name;property_name;value_name" appends some css to the html header, giving all elements of the name ‘element_name’ the property ‘property_name’ with the value ‘value_name’. For instance, to make the .BufferWindow yellow:

css-set-fast ".BufferWindow;background-color;yellow" 

is equivalent to

.BufferWindow {
  background-color: yellow;
}

The more you use css-set-fast, the longer your header gets, but it works instantly. It’s best used early on in ‘When play begins’, and then later you can just set things to the style you defined earlier.

css-set-slow does the same thing but works by using jquery to find all pre-existing elements with the given id and changing their css to the given property. It generally only changes things already on the screen. It is useful for changing text or background colors all at once.

Google Fonts

import-google-fonts lets you import google fonts. Due to space limitations on strings, the only text you need to enter is the part in the url after the first ‘family=’ and before ‘&display=swap’. So, for instance, if google says to use this import:

<style>
  @import url('https://fonts.googleapis.com/css2?family=Kalnia:wght@300&family=Rubik+Bubbles&display=swap');
</style>

You only need to type:

import-google-fonts "Kalnia:wght@300&family=Rubik+Bubbles"

Hyperlinks

hyperlink "name" as "command" creates a hyperlink that, when clicked, executes the given command. So, you could say

hyperlink "north" as "north"

and it prints out the word ‘north’ as a hyperlink. This works in gargoyle and similar interpreters, too!

“zzxvm” is a special phrase. Any command starting with zzxvm is not printed. Thus, if you want the hyperlink commands not to show up on the screen, preface them with zzxvm. An example is given in the Fake Twine game.

Sound

Sound is done using Inform’s native sound capability, so it works both in the web interpreter and in Gargoyle. The special command to be used is upload-audio [name of file] with internal name [whatever name you named it];. This should be done when play begins. It creates an audio element with name ‘Snd[number of the audio file]’. If you don’t know the number of the audio file, you can check it in Inform where it is stored as ‘Glulx resource ID of _____’.

Sounds are added to a new Sounds folder you must create in BOTH the materials folder and in the release folder. Inform does not use .mp3s, but online play for most browsers do, so you need two copies of each sound (one in an Inform-friendly format like .ogg and one as an .mp3). You technically only need the .oggs in the materials/Sounds folder just to get it to compile and the .mp3s in the release/Sounds folder to get it to run online.

Here is a typical declaration and playing of sounds:

Sound of bells is the file "Bells1.ogg".

When play begins:
	upload-audio "Bells1"  with internal name sound of bells;

Instead of taking inventory:
	play sound of bells;

This implements all of the standard glk functions, including fancy stuff like sound-notify events, volume-notify events (which have to be manually added to Glulx Entry Point’s list of g-events), but also simpler stuff like channels. This means that pre-existing sound extensions should work; I’ve tested this and everything in Music by Daniel Stelzer works except that cross fades use an older format that should be updated by someone using this.

Images

Quixe already has full image code. Bisquixe doesn’t have to do anything!

Except setting up the images ahead of time in the play.html page. There is a python script to do that, but it can be a little intimidating.

The new functionality is:
add-image (Temp - a text) with alttext (tempalt - a text) with id (Temp1 - a number) with width (Temp2 - a number) with height (Temp3 - a number) :

An example is:

Summary
Figure of pikachu is the file "pikachu.jpg".
Figure of Rembrandt is the file "Rembrandt.jpg".
	
Release along with a "Bisquixe" interpreter.

Include Simple Multimedia Effects by Mathbrush.

Sandbox is a room. 

When play begins:
	let temp be the glulx resource id of the figure of pikachu;
	add-image "pikachu.jpg" with alttext "surprised pikachu face" with id temp with width 320 with height 320;
	let temp be the glulx resource id of the figure of Rembrandt;
	add-image "Rembrandt.jpg" with alttext "Rembrandt" with id  temp with width 342 with height 423;

Instead of thinking:
	display the figure of pikachu;
	display the figure of Rembrandt;

The only caveat is to get inform to compile, you need your images in a folder called Figures in the materials folder, and to get bisquixe to work, you need to copy that folder to your release folder as well.

Internal Links

Internal links (i.e links to the same folder) can now be added by the phrase ‘link-page’ like so:
link-page "/index.html" with TabOption 1;

This manually opens a new page. To go up one in the directory, add a single period before the title (not two periods like usual). So “./uponefolder.html”.

TabOption 1 opens in a new tab, TabOption 0 opens in the same tab.

This doesn’t generate a hyperlink, it literally opens the page. To make a hyperlink, you need to combine the pre-existing hyperlinks with the ‘invisible’ commands and this new functionality:

Link Code
Sandbox is a room. "Hello! To try various features, try clicking links, typing Z to see text alignment, typing JUMP to see various colors used in the same paragraph, or typing I to hear a sound. J plays some music, K stops it, while P and M fade the music in and out when it's playing.

Here's a link to the homepage: [homelink].

Here's a link to the homepage, but opening in a new tab: [homelink2].

From here, you can go [boldnorth]."

To say homelink:
	hyperlink "link" as "zzxvm home";

To say homelink2:
	hyperlink "link" as "zzxvm home2";

Jumphoming is an action applying to nothing. Understand "zzxvm home" as jumphoming.

Carry out jumphoming:
	link-page "/index.html" with TabOption 0;

Jump2homing is an action applying to nothing. Understand "zzxvm home2" as jump2homing.

Carry out jump2homing:
	link-page "/index.html" with TabOption 1;
6 Likes

Excited to try this out. I get this error with a minimal story. I’m using Inform 10.1.2.

In Book 2 - Links, Section 1 - Initiation of links in the extension Simple Multimedia Effects by Mathbrush:

Problem. You wrote ‘Include (- [ VM_KeyChar win nostat done res […] “^”; #endif; ! ECHO_COMMANDS ]; -) instead of “Keyboard Input” in “Glulx.i6t”’ [](source:C:\Users\bjbes\OneDrive\Documents\Inform\Extensions\Mathbrush\Simple Multimedia Effects.i7x#line95): but this syntax was withdrawn in April 2022, in favour of a more finely controlled inclusion command. See the manual, but you can probably get what you want using ‘replacing “SomeFunctionName”.’ rather than ‘instead of …’.

See the manual: 27.26 > 27.26. Overriding definitions in kits

I see that your text message example uses 6M62, so I imagine that’s the difference.

But here’s my code, just for completeness:

"Bisquixe Tests" by "B.J. Best"

Release along with a "Bisquixe" interpreter.
Release along with a "Bisquixe" website.

Include Simple Multimedia Effects by Mathbrush.

Lab is a room.

Edit: I then tried this in 6M62, but then had a different error with the version number of Glulx Entry Points, which I just installed. (I’m not sure if that extension has been updated for I10, thus rendering it incompatible with I7?) I hacked a valid version number into that extension, and then I got a few more I6-related errors within that extension. So I’m not sure what’s going on there.

3 Likes

You don’t have to install glulx entry points for 6M62, it should come pre-installed with that version, but if you install one, it overrides the old one. If you check your list of installed extensions, there will probably be Glulx Entry Points listed twice.

I could remove dependence of glulx entry points by copying the related code.

I tried dual-installing inform 7 and inform 10. I’m working on updating the extension, but it looks like Inform 10 has removed the glk() function that all my calls depend on. I’m not sure if there’s a new way to make glk calls, but I’ll check!

3 Likes

Looks like Inform 10 is just very different; I’d have to basically start over in order to understand a lot of what’s going on. So I guess this is 6M62 for now unless someone wants to tweak it who knows the difference between @glk and glk() or knows why ‘replacing’ doesn’t seem to work the way 'instead of ’ does (since it says I’m defining things twice), it’ll just have to wait until I can figure the stuff out on my own, which could take a long time.

2 Likes

:joy:

6 Likes

Okay, good news and bad.

I learned the difference between @glk and glk() and have the whole extension working in v10 except for one part. That part is the one that decides whether to print back the player’s command to them after they click on a link or type in. It’s easy to make it work if the game is all typing or all clicking, but right now I can’t get the part to work that lets you alternate between them in v10.

2 Likes

I’m excited to try this out. Seems like magic to me :dizzy_face: Great work!

4 Likes

I’m looking forward to checking this out! I’m another v10 user, so I’ll focus on the typey bits.

3 Likes

Okay, I’ve added a version of the extension that works in v10 of Inform. All features work except that when clicking on a hyperlink, a blank line is printed before the command is typed in. Both of the examples should (hopefully) work. (They do on my computer! [famous last words]).

It can be found on both the main page and the release section of the github link.

6 Likes

Okay, thanks to @otistdog, even that bug was corrected.

So now the Github has two extensions:
Simple Multimedia Effects (works for Inform 7)
Simple Multimedia Effects for v10 (works for Inform 10), version 2, both with identical functionality.

The Inform 10 version requires downloading Glulx Entry Points.

The Inform 7 version uses the built-in version of Glulx Entry Points, and nothing should be downloaded.

5 Likes

I’m going to quote this explanation here so that it doesn’t get lost:

Because it's fast and easy and not quite as good as a carefully crafted product

6 Likes

Just because you can, doesn’t mean you should.

When play begins:
	css-set-fast ".GridWindow;background-image;url('70S_MARB.JPG')";
	css-set-fast ".GridWindow;color;white";
	css-set-fast ".GridWindow;font-family;Times";
	css-set-fast ".GridWindow;font-weight;bold";
	css-set-fast ".GridWindow;font-size;20px";
	css-set-fast ".BufferWindow;background-image;url('LOVE.JPG')";
	css-set-fast ".BufferWindow;font-family;Courier New, monospace";
	css-set-fast ".BufferWindow;color;blue";
	css-set-fast ".Input;color;red";
	css-set-fast ".Input.LineInput;font-family;Courier New, monospace";
	css-set-fast ".Style_input;color;darkgreen";
	css-set-fast ".Style_input;font-family;Courier New, monospace";
	css-set-fast ".play;background-image;url('GREENY.JPG')";
	css-set-fast ".coverimage;display;none";
	css-set-fast ".links;display;none";
	css-set-fast ".interpretercredit;display;none";

The backgrounds are placed in the Release folder and were taken from an HTML Clip Art CD from the Internet Archive.

10 Likes

image

12 Likes

Okay, a slightly more serious one, which I’m really excited about. Because you can import (some) Google fonts! (And use them over an awesome classic CSS gradient!)

When play begins:
	css-set-fast ".BufferWindow;background-image;linear-gradient(red,yellow,blue)";	
	css-set-fast "@import url('https://fonts.googleapis.com/css2?family=Graduate&display=swap');;";
	css-set-fast ".BufferWindow;font-family;Graduate";

(I think I’m kind of abusing the way css-set-fast is supposed to be written when importing that font, but it works, and I’m happy!)

But! That @import line gets too long for many fonts. For example, if I want to try the Rubik Bubbles font, the code is: @import url('https://fonts.googleapis.com/css2?family=Rubik+Bubbles&display=swap')

But when I open the browser dev tools while running Bisquixe, it looks like it’s getting cut off: @import url("https://fonts.googleapis.com/css2?family=Rubik+Bubb { undefined: undefined; }

For comparison, the functioning code for the Graduate font above is: @import url("https://fonts.googleapis.com/css2?family=Graduate&d { undefined: undefined; }

Would it be possible to extend the length of whatever string is getting passed so longer font names could be used?

7 Likes

So all the strings get passed through glk which has a ‘convert to c string’ thing which I think limits the size of the string.

The nice thing though is that while this lets you mess around with css directly, part of the reason I wanted to create this was to make it easy for people to experiment with css in the game, and then they could copy their finished creations to the actual game .css files later.

If you go into the template folder that you put bisquixe in and edit glkote.css, you can make these changes permanently. In this case, you can edit .BufferWindow’s css. If you want to make changes mid-game, you can add a new style like

.FancyFont {
@import
}

and then use set-any-style to turn that on mid-game.

Other than that, I can investigate lengthening the strings, but I’ll have to poke around.

3 Likes

Yeah, that makes sense. I think part of the issue is that I feel a lot of things in the CSS aren’t intuitively named (from the author’s side; I imagine they make sense on the programming side). Based on name alone, it isn’t obvious that .GridWindow is the status line, for example. Or that in order to change the game’s CSS, you need glkote.css in the interpreter folder rather than the more expected style.css file in the Release folder.

Obviously all of this could be learned / overcome. But if Google fonts could be accounted for in the extension, I think that’s pretty much perfect–all CSS could be adjusted directly in Inform with no need to ever look at a CSS file if one would prefer not to. (I do think a cheat sheet of what the CSS elements are in layperson’s terms would be helpful–it took me a while to figure out the .Input and .Style_input stuff. I’d be happy to write something up, though I imagine there are those far more qualified than I. I mostly just hack things together until they work.)

Anyways, I think this is incredible. So cool.

4 Likes

Do the urls always follow a specific pattern? If the url always starts the same way then I might be able to make a function just for google fonts where you type on the last part of the url; that should fix it. Zarf gave me room for 16 functions and I’ve only used three.

A guide from you would be great, since even if others know more your audience would be people like you and me trying to get started, so you would better appreciate what is confusing and what is simple.

2 Likes

Yeah, at a basic level, they’re always the same:

'https://fonts.googleapis.com/css2?family=[Font+Name]&display=swap'

If the font name is a single word, then it’s family=Name. If there are two words or more, the words are separated by pluses: family=Font+With+Four+Words.

Google wants all of the fonts imported at once, so if there are two or more, those are joined by ampersands. For example:

@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Roboto&family=Rubik+Bubbles&display=swap');

Awesome! I’ll work on something and share. I also want to just kind of play a bit and see if there’s anything else interesting that could be done easily. But I bet a basic guide for folks for backgrounds, colors, and fonts would be enough for people to do some cool things.

One other idea: Would it be possible for an author to write something like:

css-set-fast "StatusLine; color; blue";

And have the extension replace “StatusLine” with “.GridWindow” behind the scenes? Some substitutions like that might aid in further readability.

2 Likes

Hmm, that should be easy. I can just make a bunch of special case functions. I have worried about tradeoffs; providing a lot of special cases makes it much easier for people who know of them all, but makes the extension more intimidating for new people. But it can’t hurt to try, so I’ll make them and see if people like it better or worse.

I can definitely make the google font thing, easy, except for the ampersand thing; if people want to use a lot of fonts, it’s not all going to fit. I’ll have to learn how to pass arrays of strings through glk if I’m going to get that to work. I’ll try it though!

Looking forward to any guide! There’s no real rush, so anything you do with it is great!

2 Likes