Vorple equivalent for Dialog/the Å-machine: feasibility, interest, thoughts?

I started trying Dialog recently, and it’s possible I like it better than Inform 7. However, I also like Vorple a lot, at the point that not having Vorple for Dialog is a blocker for me. So I’m considering if it’s possible to create something like Vorple for Dialog.

(For those unfamiliar with Vorple, it’s a special Glulx interpreter that makes it possible to execute arbitrary JavaScript code from within the story.)

Here are some thoughts. (It’s a long and a bit technical post, so you may ignore it if you don’t need this kind of features.)

I took a look at the Å-machine web interpreter, and since the engine and the front-end are nicely decoupled (I always found Quixe and its Glk API a bit tangled and complex), I think it should be possible to write a custom Vorple-like front-end. But for that, two things need to be solved.

First, sending JS commands to the webpage. I thought about using a (inline) status bar with a special class, in which we output our JS code. The Å-machine front-end would hide it and watch its content to execute it. We could maybe use a div or a special markup in the output ([JS]alert("Hello")[/JS]) instead, but a status line doesn’t end up in the transcript and seems easier to handle.

Second, retrieving the returned JS value. This one is more tricky. I suppose we could ask for a line input just after sending a JS command, and the front-end will send back an input just after executing the JS command.

It would be something like this, Dialog-wise. It’s written quickly and untested, it’s just to get the idea.

(global variable (JS returned type $))
(global variable (JS returned value $))

(execute JS $Closure)
    %% Output the command into a special inline status bar.
    (inline status bar @vaarple) (query $Closure)

    %% Then the interpreter will send the type of the returned JS value.
    (get input [$ReturnedType | $])
    (now) (JS returned type $ReturnedType)

    %% Then the interpreter will send the returned JS value.
    (get input $ReturnedValue)
    (now) (JS returned value $ReturnedValue)

(program entry point)
    Making a JavaScript alert.
    (execute JS { alert\("Hello from the JavaScript!"\) })

Once sending messages to and from JavaScript works, the rest (input and output filters, multimedia…) should be relatively easy to write on the interpreter front-end’s side, or so I hope.

Issues I see for the moment:

  • All the parentheses in JS commands will have to be escaped. Unavoidable, but annoying nonetheless.
  • JS commands will have misplaced spaces in it. For example, Dialog will automatically insert a space before the parenthesis of a function call except if we use (no space). Mostly harmless, but I suppose it can cause strange issues sometimes.
  • There might be misplaced line and paragraph breaks after executing a JS command? For example, in Vorple, there is a function that redirect all output to a given HTML element; we’d have to track if a paragraph break is pending for each of these elements, or be very careful otherwise.
  • Retrieving the values returned by the JS with a line input limits them to lists of dictionary words and numbers. (It won’t be possible to retrieve the exact command as it was written, with its case and white space preserved, for instance. Or it might fail if the returned value contains some unsupported Unicode characters.)

Is something like the above a good idea, and is there some interest in it? If yes, am I right to think it’s possible to implement it with the Å-machine? Have you got better ideas to communicate with the JS? (Or maybe someone is already working on something similar?)

I’ve got no plans in the near future, but I’ll likely try to implement something like that if/when I get serious with Dialog (and the possibility of a Vorple-like interpreter is a reason I might get serious with Dialog).

Thanks for reading!

3 Likes

Vorple 2.5 supported the Z-Machine. You could try porting its I6 extension to Dialog.

2 Likes

I did think about using Vorple 2.5, but it uses custom opcodes and other low-level code, and that kind of thing is not accessible in Dialog.

Also, my opinion is that ideally it would be best to use the Å-machine since it integrates better with Dialog (although I’m OK with the Z-machine if it’s the only way).

Anyway, even if it was possible, I’d rather not depend on something that isn’t maintained anymore.

2 Likes

Well, I just want to say “I’m interested”! Being on Linux, I’m essentially shut out from using inform 7 at the moment due to the giant flatpak download, and I’d really like to be able to use/learn vorple.

(I really like Dialog, particularly its interactive debugger, it’s not the case that it’s second best or anything.)

5 Likes

Regarding Inform 7 on Linux, you could instead download the CLI interface, and use another code editor. (I’ve made an Inform 7 extension for VS Code that makes it possible to compile from within VS Code and highlights errors, for instance.)

Back to the original topic, what I have in mind won’t be exactly like Vorple. I prefer something simpler and more modular, but I guess I’ll have to strike a balance between my own needs and the general public’s needs.

(What I mean is that Vorple comes with its own fonts, tooltips, notifications and the like, which I usually don’t need. But I understand it’s cool for those who are not familiar with web development. But before thinking about all that, I should see if a Vorple for Dialog is possible at all first, of course)

2 Likes

No custom opcodes or file operations sure limits your options. Input stuffing does seem to be the most elegant way to communicate back to the VM. Between (get input) and (get key) you should be able to kludge something together.

For dynamically generated JavaScript, the special status line idea seems the best, but for static JavaScript I recommend using (embed resource) with a .js file. Then you can use (can embed) to detect JS support.

2 Likes

Embedding the JS files in the story is an interesting idea! But I don’t know what to think about it.

On one hand, it makes it possible to design a unique interpreter that could play every Vorple-Dialog story files. The default presentation would be bare-bones, but each story could embed JavaScript to create their own experience.

On the other hand, authors can just customise the interpreter and include their JavaScript files directly in the HTML page with a <script> tag. Also, what about authors who want to include the interpreter in a larger JS project with, say, React, webpack and so on? I guess we can support both ways (load any story-provided JS along with the JS already on the page). I can see how it could make it easier for those unfamiliar with web development.


Regarding (interpreter can embed $) to detect JS support, it’s a very good idea! It might even possible not to include anything:

(define resource @vaarple) vaarple-is-supported

The compiler will complain that the file doesn’t exist, but the story file is still created. On the interpreter’s side, you’d just check if the ressource name is “vaarple-is-supported” and return true.

1 Like

So after investigating a bit, it turns out the class name of the status bar is not stored in the compiled file and is replaced by a numeric index. That makes it more difficult to know which status bar is supposed to house the JavaScript commands. (In my example, the interpreter won’t be able to know into what number was @vaarple converted.)

One solution that occured to me: use CSS custom properties (a. k. a. CSS variables) to encode information into the class. (Since they don’t have meaning of their own and can contain arbitrary data.)

(style class @vaarple)
    --vaarple-js-eval: true;

On the interpreter’s side, we look for the presence of the --js-eval property to know that a given class is the one for executing JavaScript commands.

Extending this concept, we could have arbitrary streams/windows that are configurable!

(style class @my-stream)
    --vaarple-clear-on-enter: false;
    --vaarple-name: side-window;
    --vaarple-in-transcript: false;
    %% And so on.

Of course it feels a bit hacky. :grimacing: The other solution is to plead Linus for a ENTER_STREAM opcode for arbitrary streams of text whose purpose is decided by the interpreter.

But I just discovered his answer here, and he seems to be against a feature to execute arbitrary JavaScript because it’s not future-proof.

So Linus, if you’re reading this, here’s my take: the point is not to be able to execute arbitrary JavaScript, but to be able to send arbitrary data to the interpreter (which can of course ignore it). I agree, it’s not future-proof and locks your story to a single interpreter, but that’s by design: the aim is to be able use Dialog as a middleware in a bigger game/engine (in the same vein than ink), and not only as a standalone story creator. In other words, to broaden the uses of Dialog. If an author wants to make a non-future-proof online game with Dialog, then that’s their choice and they accept the compromises it comes with. It doesn’t prevent others to make regular plain stories.

But the final decision is yours of course, and I respect that. :slightly_smiling_face:

1 Like