How about a new minimal IF engine with complete source file control?

Hi all! I recently made a (quite complicated) IF game in Twine with Snowman and the fact that I couldn’t organize my HTML/CSS/JS code the way I wanted was something I found quite frustrating. As a matter of fact, I just did everything in a separate VSCode project and just copied/pasted all the time (had several minigames and a lot of logic so a lot of JS involved).

So, I came up with the idea of building a new minimal IF engine for choice/hypertext-based IF works, with basically 2 features:

  • Showing a graph of your story’s passages and letting you manipulate them, just like Twine

  • Having a “Build” button to export your game to a single HTML file, again just like Twine

The key difference would be that all of your files would be in your file system in a project folder and completely controlled by you/edited in the editor of your choice. Expanding on that, other features of the engine could be that creating a new passage in the graph view would create a new HTML file or folder in your project directory, where you could then write anything you want to appear on this passage (probably by using EJS in HTML), and even allowing you to have separate “js” and “css” folders inside each passage, further separating logic if necessary - I have many minigames in my stories, so that is something I’d love to have. Also, another feature would be tag-based logic, where you could have “semi-global” JS files that would be “appended” to all passages with a specific tag, allowing you to embed specific logic to specific passages.

All this is just an idea at the moment. I was wondering what do you guys think about it? Do you use code (mainly web technologies) a lot to customize your games like me? Would that be something you would use/be interested in? I would really love to hear your opinion on this. Cheers! :slight_smile:


You can actually already do a lot of this with Twine in VSCode using Twee and the Twee 3 Language Tools plugin.

Personally, I’m happy enough with that, and in particular I don’t think I’d be interested in a tool that broke every passage out into its own file or folder for editing purposes. My longer games have hundreds of passages, and with Twee I can break my (e.g.) 285 passages into 12 separate Twee files using groupings that make sense to me rather than having to sort through 285 files in the VSCode sidebar. I also can’t think of many cases in which I would want my CSS or JS to apply to only a single passage as opposed to a subgroup of passages. I get the impression from what you’ve said that your JS-heavy minigame approach results in a pretty low passage count relative to the amount of content in your game, but I think that may be a bit of an outlier relative to how most people use Twine, if you want this to be a substantially Twine-like tool.

But the idea of semi-global JS using passage tags is intriguing, and I can see there being some interest in that. I also know some people around here strongly dislike VSCode and I think it may be the only code editor that has a plugin that gives you the Twine-editor-like graph view, so there may be some interest from people who want to use other editors and still have the graph view.


That is a very informative response, thank you so much! I haven’t used the Twee plugin actually, I might want to try this out.

But my main consideration was the per-passage (mainly for code-heavy minigames) and per-tag (for groups of “similar” passages) CSS and JS, and I haven’t really found an efficient/clean enough way to do this with Twine. I also envisioned this as having HTML/Markdown files to edit for each passage instead of Twee - and therefore having no engine-specific “language” to deal with.

But I’ll definitely check Twee and see if that’s enough for what I was lacking my first time round.

1 Like

I didn’t mean to say Twee would do everything you would want for the way you structure your games (though it definitely could have saved you some effort copy-pasting from VSC into the Twine editor)—I can see why you need the per-passage CSS and JS. But since this seemed to be a general interest check, I wanted to say that I’m not sure how many other people (1) are structuring games this way and (2) specifically want a Twine-like tool with which to do it.


I’m always suspicious about graphic showing linkage. Seems to me that you need to manually arrange the nodes as to be show the story progression in a clear manner. The graph in Detroit: becoming human looks clear enough, but somewhat extensive.

Regarding the program/engine, I like to repurpose things, so maybe something like usenet news reader/threaded message board with the difference instead of buttons for prev/next topic, you’re presented with “see also…” but with the game story choices.

This can be done with Reply-To header as per Usenet packets, but with custom display.


Fully concur & agree on repurposing (visual) things, this should be of great help in ensuring UI consistency. but let’s not forget that the main advantage of web IF coding lies in the most complete gamut of styles &c available under HTML markup.

Best regards from Italy,
dott. Piergiorgio.

1 Like

I’m forever feeling like “this Twine authoring system was not quite made for me”. I really like it when I can make my own language of sorts in the Twine story formats. I wish I could simply link to an external JS file in the <head> tag so it would load before any content did. It’s not a smooth experience to use external libraries in Twine story formats.

I’m not sure what the perfect system would look like, but I keep going back to exposing HTML, CSS and JS so that authors actually learn web technologies as they code web-based IF. Still, Twine seems to be the best at what it does so far. I’m still happy to use it, but it’s not as versatile as it could be. Off the top of my head, collapsible trees would make authoring much easier and having a smoother zoom in and out system for dragging the view map around would do wonders.

Off Topic: I’m extremely interested in Snowman, given that it seems to be made as a bare bones framework that encourages customization. Are there any resources you can recommend to learn Snowman?


I also loved Snowman because it gets rid of the crap (for me) of making you learn a new story format-specific “macro language” which is also bound to be limited to some extent and let’s you create with a real, full-fledged language like JS, giving you the full freedom that this entails for your logic and/or your game style. However, I had a really hard time learning how exactly Snowman works…

To be specific, after learning the basics of the Twine ecosystem, I used the documentation of Snowman as well as the “Twine 2 examples” section of the cookbook. I’m afraid I couldn’t find any other good source… But I still felt limited to a certain extent. For example, I changed the code of Snowman in order to be able to have a land page after one loads their game from a save file (effectively adding a callback to the restore function).

Having said all that and read all of your valuable comments, I think I’m gonna attempt creating an MVP of an engine, at least for fun. No GUI, no graph view for now (in retrospect, after ~10 passages, it didn’t really add any value for me). So, I’m gonna post a roadmap of how I envision it to work and hopefully get some invaluable feedback from you guys :slight_smile:


That sounds like the best way forward. Even the landing page thing you did was something that I had to wrangle up in Chapbook.

What you found for Snowman reference is what I’ve found. Still, the Cookbook is quite useful.

I even made up my dream macro-language at one point on paper (we still need to put conditional logic and variables in the text that’s displayed and identify areas to be updated dynamically, etc.) I’d love to see how you propose handling those kinds of content scenarios. What will the mixture of JS and content text look like, I wonder.

My biggest pet peeve is that the story formats have built-in CSS styles and sometimes HTML structures. You have to undo stuff before you can do stuff, if you catch my meaning. If you do end up, making a default layout design for your idea, make a version that actually is bare bones aesthetically too, please.

I’m very much interested. Keep us updated!


When I was working with Twine I found Twee/Snowman was the best fit for me. As an experienced (if not enthusiastic) user of Javascript, Snowman mostly just got out of the way.

The downside is I ended up with a bunch of JS libraries (inventory, event system, maps, …) and realised how little Twine was actually doing for me except create constraints I didn’t find particularly inspiring. That was the point where I realised what I was doing wasn’t a great fit for Twine (for me).

So I started working on Rez which was envisaged as a “weekend replacement” for Twine. A year later and it’s almost ready, though much of that time is my occasional development pace and greater ambitions.

Why I think this is relevant is that Rez has a mostly declarative source format that allows for plugging in JS functions as attributes that are run by the various systems (e.g. event handlers, behaviours, or procedural generation).

Here’s an example:

@actor player begin
  given_name: "Sam"
  family_name: "Spade"
  full_name: ^p{`${this.given_name} ${this.family_name}`}
  description: """
  Sam Spade, with his sharply chiseled features, appeared as if he had been etched from the foggy streets of San Francisco itself. Tall and lean, he moved with a predator's grace, seemingly always alert. His eyes, sharp and discerning, missed little, hidden under hooded lids that often gave away nothing of his thoughts. They were the eyes of a man who had seen too much, who carried burdens, and who could pierce through lies. 
  on_fire_pistol: (sam) => {
    const pistol = sam.inventory.getContentsForSlot("weapon");
    if(pistol.bullets > 0) {
      return {card: "pew_pew"};
    else {
      return {card: "click_click_oops"};

The ^p{...} part simply says “make this into a property”.

To me this feels like quite a natural model for working with attributes, content, and scripts. (I mean it would be funny if I didn’t think so given I wrote it).


That’s extremely interesting actually. Do you have a link to a website or a repo? I totally agree with what you said about Twine and Snowman, I feel exactly the same way. In the following days, I will have completed an MVP of an extremely minimal engine that will basically replicate Snowman to an extent, but giving the user full freedom regarding the organization of their text, code and styles, as well as a lot of extra customization options. I’d love to hear your opinion when I publish it, and I would also love to take a better look at Rez!

1 Like

Yep Repo, Docs. Happy to take a look at what you release. FYI Rez is written in Elixir and compiles to JS/HTML.


I’m super excited to finally share iffinity with you!

It’s in an alpha state, but I think it is more than a working MVP! You can view the source code in the link, as well as its complete documentation here. As I mentioned previously, it is heavily based on Twine/Snowman, but I think it grants a lot more freedom to the author. It is distributed as an npm package, so you can just npm install it if you want to play around with it. There are a couple of example stories in the repo, and after installing it you can also create a working template project with ifc init and see the engine in action right away.

I can’t wait for your opinions/suggestions/thoughts! Cheers!


Great name!


Cool. I think you’ve nailed the deployment story (a definite weakness for Rez) which is a key thing when proposing a new tool. I think I would definitely have tried this back when I started to get frustrated with Twine.


This looks really interesting. Sugarcube, which I’ve used for a lot of stuff, doesn’t support code-heavy passages that well, and I haven’t tried Snowman, but as an even more lightweight alternative this is definitely something I’ll have to check out.

1 Like

Looking forward to your thoughts and suggestions if you do try it out! I’m also open to collaborating on the codebase itself if anyone is interested :slight_smile:


Okay, I did a minimal bit of testing by trying to port over a WIP I’m making using Sugarcube (Twee) + Typescript. It didn’t exactly work? I was using esbuild to turn the Typescript files into one large JS file I could include in the Sugarcube project, but when I tried that with Iffinity it kept giving me a white screen plus Uncaught SyntaxError: expected expression, got '<' while compiling ejs in the console. The game worked when I didn’t include the JS file in iff-config.json, but since most of the functionality is in the Javascript it’s just a bunch of empty divs without it. (My code is on Github if you want to look, with most things in the src2 folder and export/index.html containing the exported HTML file. It doesn’t really do anything, though, and the game isn’t even done yet, so I don’t know how much that would help.)

A few other questions I have:

When configuring the story JS file and CSS file in iff-config.json, is there any way to have multiple JS/CSS files in one line? e.g. multiple CSS files for the story CSS? The Typescript type says it only accepts a string, not a list of strings (file names). I couldn’t figure it out.

Is there a way to edit the HTML around the area where the current snippet is rendered (the equivalent to altering Sugarcube’s special StoryInterface passage)?

With all that said, the amount of work put into this is still really impressive. I have basically no experience working on Node packages, so I don’t think I could help with development much, but I wanna see where this goes.


Thank you so much for trying iffinity out! Feedback from real users is the most valuable thing at this stage.

So, I took a look at your project and, strangle enough, by opening the exported vapormall.js file in VSCode and saving it without changing anything, just allowing VSCode to format it, I don’t get the error you mentioned (which I did get before, like you). I sincerely have no idea why this happens, probably has something to do with how esbuild exports TS to JS, but I’ll definitely need to look into this. For the time being, if you would like, please “pretty format” vapormall.js and try again, to see if everything else works out for you moving forward. I’m extremely interested to find out! Here it is (42.1 KB), formatted, for your convenience (I added an .md extension so that I could upload it).

Now, regarding your questions:

  1. There is no way for the time being to have multiple JS and CSS story files, which is quite stupid of me. I’ll patch this as soon as I can. As a matter of fact, I’ll make all script fields in the configuration file of type string | string[], so that you can have as many as you like. This part of the design is not very clean, for example libraries are lists of strings, story JS/CSS are a string expecting a single file and tag-based JS/CSS are strings that however allow multiple space-separated files like "script1.js script2.js", which is yikes. But it’s not hard to fix, so I’ll do it promptly.

  2. I’m not familiar with SugarCube, but I was thinking how to deal with this myself. Being minimal and all, I decided to do a little refactoring. For the time being, the output html is roughly like this:

    <div id="iff-snippet">
        ... active snippet content ....

So, right now, you can add things around it be prepending/appending elements directly to the <body>, using jQuery, for example.

I’m thinking of adding another “wrapper” layer around the active snippet, so that the author can have more freedom to do stuff like what you said, without the ugliness of having to mess with the body itself:

    <div id="iff-story">
        <div id="iff-snippet">
            ... active snippet content ....

I will also change this as soon as possible (it will help in other aspects of the engine, too). For the time being, you can experiment with prepending/appending stuff to the <body> directly, via JS.

I’m really looking forward to hearing from you and for the next steps in your project!


Actually you helped me find a very tricky bug (obviously it was my fault and not esbuild, like, obviously…)! Thank you so much! I fixed it, but I’ll need some time before I upload a new version.