First time sharing a TypeScript based IF development system (IFECS)

Hello Interactive Fiction Community,

I’ve been secretly working on an interactive fiction engine called IFECS (maybe pronounced effects). It still needs a lot of work and documentation is pretty much non-existent but felt it was time to start sharing. Obviously I’ve been testing other development systems and many are really great (Inform 7 is genius). But as a developer I wanted to try something different (I know, I know… queue XKCD). Anyway, here are the key points that I think make IFECS somewhat unique.

  • At its core IFECS uses a fairly traditional and simple ECS (i.e. Entity, Component, System) engine. On top of the ECS I’ve layered an interface that makes the engine feel like object-oriented programming when it comes to the actual game development. One top of this is a DSL (Domain Specific Language) for building interactive fiction games.

  • The entire system (engine, interface, standard lib, games, etc) is written in TypeScript. My hope is this eliminates barriers between the engine and game development and makes the system a lot more open and developer friendly. No black boxes and a single programming language.

  • I’m using Deno as the runtime. I think Deno adds a lot of interesting options for publishing and sharing and provides some useful common tools for linting and testing.

Here is a Cloak of Darkness playable on Replit: https://replit.com/@Hypercubed/Cloak-of-Darkness?v=1

Here is the source code: GitHub - Hypercubed/ifecs

Constructive criticisms, suggestions, and pull requests are appreciated!

5 Likes

Do you have any info about the DSL for people to look at yet? Looks like so far all your examples are written in TypeScript.

Congratulations on developing your IF platform! I wish you the best of luck.

How do you imagine players would normally play IFECS games? In Replit, as you’re demonstrating here? Would there be a web UI runner for ordinary folks? Would players be expected to install deno locally to run an IFECS game? Would deno generate standard Z-code or Glulx files?

(I notice that when I attempt to run Cloak of Darkness in Replit, it takes 30+ seconds to launch, because Replit makes no attempt to cache downloaded deno dependencies; it downloads and redownloads (and rechecks) all the deno.land dependencies every time I refresh the page and click Run. That seems like a non-starter for regular folks who just want play a game. I literally thought it had crashed at first!)

I suggest that your next step be to write an “admirable” game in IFECS. (I say this to all new IF platforms that launch with just a tech demo.) Most people choose an IF platform by playing a great game and saying, “I really like this game, and I would like to make another game just like it. How did the author(s) make it?”

So, when IF platforms successfully take off, they require an admirable story (not just a technology demo) to attract new authors. Historically, the first “admirable” story for each now-successful IF platform was typically either written by the platform authors themselves, or directly funded by them. (Twine’s first admirable story by Anna Anthropy is the only exception I’m aware of.) Admirers don’t seem to directly care about any of the details of the system, except that if it’s too hard for them to learn the system and finish a game, that’s a major factor in achieving true popularity.

I think you’ll either need to write something great or hire a great writer (preferably paid in advance) to launch your platform effectively.

2 Likes

Hi @JoshGrams , maybe I’m using DSL too loosely here. I consider the action system a embedded domain-specific language, so yes. Written in TypeScript.

Hi @dfabulich,

I’ve tried to separate the interface from the engine itself so it is very possible to run a game within a web UI. For most of what I’ve been doing so far I’m running right off the terminal. The terminal interface starts up much faster than Replit (which is supposed to be caching too :unamused:). With Deno it’s also possible to compile to an executable that that could be a way to distribute. Generating Z-code or Glulx is pretty far out of scope for me at the moment.

I hear you load-and-clear regarding an “admirable” story. It’s going to be a difficulty for me… I’m not much of a story teller. Also, I don’t have any expectation that my approach will be very popular for non-programmers. Hoping some people find it useful; or at least as interesting as I do.

Is that possible today? Or do you mean it would be possible for someone to write a web UI, but nobody yet has, so it is not yet possible?

Distributing executables to ordinary users is surprisingly hard. Windows 10 out of the box won’t even run ordinary .exe files that aren’t sufficiently “popular.” (You can notarize and pay for signatures, etc. but ordinary IF authors won’t do that.)

As a result, it’s easier to teach users to download a runner (which can become popular enough that there’s no error message) and then open an IF game file in that runner.

If not Z-code or Glulx, I think you’d want to be able to generate an HTML file that someone could double-click on to start playing a game.

As for your TypeScript internal DSL, I (like Josh) didn’t realize that you meant for authors to write games in TypeScript, and I have some feedback about that.

It’s not uncommon for IF enthusiasts to present this forum with alternate IF authoring systems in which authors can develop IF with a “real” programming language, typically one that ranks highly on StackOverflow’s “most loved languages” list.

But these authoring systems never seem to gain traction. None of the most popular parser-IF systems require authors to use a “real” programming language. All of the most popular systems use an “external” DSL for IF.

Why is the IF community so enamored of DSLs? This isn’t like other parts of the game industry. In the game industry in general, even if people do decide to implement their own engine from time to time, the most popular game engines use popular general-purpose programming languages, the same languages everybody else uses. The IF community must be full of weirdos, right?

Well, yes, but we’re not the only weird ones. Consider querying a database. You could do it in C or in JS, and some people do, but the industry has discovered that using a declarative query language is better, and SQL is by far the most popular language for doing it, despite the fact that SQL doesn’t have much in the way of step-wise debugging support. If you’re querying a database, trust me, you should just use SQL. (At a minimum, you should learn SQL before attempting to query a database in another language.)

Text adventures aren’t like other programs that run step by step from beginning to end; they’re programs to cooperatively generate text, incorporating commands from the player while subtly guiding the player how to use the correct commands to win. Coding a parser-based text adventure is mostly about declaring data (what are the rooms and objects in the game) and a rules engine of events that fire when certain conditions occur.

And, of course, that’s what you see in IFECS. IFECS “Typescript” includes backtick template strings to parse action queries (written in strings), associated with event-handler functions.

The general industry wisdom when it comes to rules engines is that they all kinda suck. It’s easy to get started rolling your own rules engine, but it’s hard to write a good one, so everybody just rolls their own. And this is another area where DSLs often do thrive. (The article I linked above is by Martin Fowler, who concludes, “there’s a lot to be said for avoiding rules engine products.”)

Then, when you add in the fact that most IF authors see themselves as writers first and coders second (if at all), you start to see why a community has formed around DSLs for text-adventure rule engines, and why good programmers keep writing their own IF-rules engines rather than use anybody else’s.

Consider also that a lot of folks appreciate IF due to nostalgia for retro hardware. (I note that you’ve styled your demo to make the text appear slowly, like over a BBS from the 1990s.) A lot of people who enjoy that sort of thing tend to want their games to actually run on old hardware, or at least run on emulators for old hardware.

You’re not gonna run TypeScript/JavaScript on an Apple IIe. You’re not gonna run Python, there, either. But you absolutely can write Z-machine code today in Inform that works on Apple II out-of-the-box.

I suppose you could write JS that transpiles to Z-machine code, but probably only a subset of JS, at which point what you have is a JS-like DSL.

I’m telling you all this not to be discouraging. I think the world could be a better place with a popular IF engine oriented around a general-purpose programming language, and especially if someone were to implement a rules engine for JS that people love, not just for IF, but for all sorts of rules-engine shaped problems.

The path up this mountain is littered with the frozen corpses of others who have tried and failed to reach the top, but I hope somebody manages to climb it, and I wish you the best of luck.

P.S. One more parting thought. Rather than write your own admirable IF from scratch, you might find it productive to port an existing IF game into IFECS. Emily Short’s Bronze is available under Creative Commons. Porting it to IFECS would probably be a valuable exercise.

2 Likes

I very much appreciate your input. While discouraging it’s not unexpected. I’ve been rummaging through several “frozen corpses” of what look like really great projects. And indeed I’ve been trying to explore the rules engine path; but at the same time trying to leverage the power of ECS.

No… a web interface does not exist. I’d need to build out a web UI or work on interfacing with GlkOte.

It looks interesting. I think that Javascript or something that compiles to Javascript is the obvious choice for a basis for an IF development platform given how much interest there is in something being playable on the web. Or at least somewhat more obvious than, say, compiling one language to another language that compiles to machine code for a virtual machine that we then run in a browser in a javascript wrapper around a C VM emulator that’s been compiled to web assembly.

Given that I think the potential to run browser-native would be one of the advantages of a JS-based system, I hope you do pursue an integration with glkote. And that would open up the possibility of letting people play with the language in a browser, too. (I’m not suggesting it’d be the ideal way to develop, but letting people take it for a spin without having to install anything would be a nice feature.)

3 Likes

Of course, the trick is “what is admirable game?” And the answer is as varied as there are gamers.

I have been very impressed with Inkle lately. Of course, their “80 days” is quite famous, justifiably so. However, I was really impressed with their “Heaven’s Vault” game. Imagine my disappointment when I realized that it’s basically

  1. Choice based ( read low tech)
  2. Unity 3D Integration is really difficult to do.

I think Twine and Renpy have had their moment of glory. I’d watch inkle development closely, because I think their games are really popular and getting even more so.

I prefer choice-based IF than parser-based IF. And there’s seriously nothing low tech about it.

2 Likes

OK, I spent some time digging into the Cloak of Darkness example. Since IFECS hasn’t been around for 28 years, it doesn’t do as much for you as Inform7 does, nor would you expect it to. But it also feels like it breaks behaviors up oddly, in ways that I’m not sure are helpful?

The IFECS code is nearly 40% longer than the Inform7 code, and a fair chunk of this feels like boilerplate. It’s also missing some functionality. Some of these things are trivial: allowing the player to type “velvet”, “dark”, “black”, and “satin” for the velvet cloak. Others would probably be more work: allowing you to wear and remove the cloak, allowing one non-going action in the dark room before the message is trampled (you just have neat/trampled where the Inform7 version has neat/scuffed/trampled), having the hook description code be robust enough to show any future objects that might be placed on it if the game was expanded.

I think the weirdest and most worrisome thing to me is that entity types don’t seem to come with default rules and commands. Am I missing something here? I feel like that’s the whole point of having a library: if you declare something as a supporter you should be able to put things on and take them off of it, its contents should be listed in descriptions, etc., without any further work on the part of the author.

Here you’re defining a custom put this on that command. And that code calls the nouns cloak and hook even though this (mostly) seems like generic code that could apply to any supporter. And you’re using a whole bunch of if-statements inside the one function to check things like “does the actor have the object?” and “is the actor wearing the object?” This doesn’t feel very extendable: you’d have to copy the entire function. What if several different parts of your game want to add their own extensions to the put command? In a rule-based system I think these things should be separate rules that can be added and removed individually without knowing about any of the others. Maybe that’s an ideal that other systems don’t actually approach, but I think Inform7 gets closer than this?

And you define the hook as a supporter. And the Supporter class has a lookable component that seems to list all visible children. But then you ignore that and create a custom examinable component (how are lookable and examinable different?) that only checks to see if the hook contains a cloak? And ok, this is the same thing that you’d do in Inform7, you’re replacing the description. But there you can re-use the internal piece of the default code by saying with [a list of things on the hook] hanging on it instead of having to copy/paste the whole code with all the problems that code duplication brings.

So…yeah. Longevity concerns aside (will you still be able to run these games 30+ years from now?), I think it’d be neat to see a web-native IF engine, and this is a fun prototype, but I don’t think you’ve quite found the sweet spot yet…

3 Likes

This is something I’m still debating. In most IF systems actions are attached to entities while in an ECS the actions should be in a system. IFECS has an action system and a “eDSL” (using the term loosely) for defining actions. Many default actions are defined in the standard lib (You may have missed the put action in ifecs/putting.ts at main · Hypercubed/ifecs · GitHub) and then the game defines more specific rules to handle specific things like “put cloak on hook”. I’m still iterating on methods to let the specific actions be less verbose (something like before or after hooks).

Thank you for the comments. So far I’ve been focusing on running in a terminal but seams to be a lot of interest in web-native.

1 Like

5 posts were split to a new topic: Tech of IF

A few tweaks and IFECS works nicely in GlkOte:

CodePen: https://codepen.io/Hypercubed/full/poPjmyJ

6 Likes