ANN: Rez — a language, compiler, and runtime for creating HTML-based interactive fiction games

I haven’t looked at them in great detail, but I am not happy with what I have seen. The tagged literals, which I guess I would need to implement the helper functions I am using, are especially strange and unintuitive to my eyes.

I did think about implementing something custom, I don’t need all the complexity that Handlebars offers, but it wasn’t a priority.

1 Like

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

I have a standard piece of advice that I share with developers of new IF authoring systems.

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. (If your system doesn’t even have one full game written in it yet, then I think it doesn’t make sense to post a link to Github with an example demo and hope/expect that an early adopter will show up and do it for you.)

Writing the first good game yourself is also important because there are already competitive choice-based IF platforms out there, including Twine, Ink, Adventuron, and our platform, ChoiceScript.

Your platform is also in competition with authors who just want to write their own platform, like you did. Developing a work of choice-based IF is often a novice programmer’s second program, literally right after “hello world.” It’s one of the recommended projects in JavaScript for Kids for Dummies. (Chapter 16: Choose Your Own Adventure)

All in all, Rez looks great, and I believe you can build a community around it if you’re willing to put in the work/money required to write a great game.

3 Likes

Hi Dan.

Thanks for the insight; everything you say makes sense, with the caveat that our perspectives may differ; I built a tool primarily for my satisfaction. I’m not starting a games company. If I am the only Rez user, well, it’s still served its purpose.

Like most creators, I hope my creation may be helpful to and find favour with others. But the rationale for Rez is quite specific. I don’t imagine someone considering using Choicescript would also consider Rez.

I agree a “good game” is an encouragement to people to try something. Whether mine will be good or even finished is an open question at this point. I guess we’ll see.

Thanks again.

Matt

2 Likes

A few other people are giving unsolicited advice about how to help this get off the ground and I will too!

Seeing your coin example, I see that the default style / html is: “completely unstyled”.

I think if you had a default html/css template and very simple look-and-feel (like Twine does) it would help people get off the ground getting a story working and then they could easily circle back to refining that look-and-feel.

1 Like

Fantastic job on your IF system. I’m always interested in new systems. How else will IF evolve? You should add more media support in your system; pictures, sounds, animation, etc.
best of luck.

1 Like

Thanks jkj.

Essential support is there for pictures. I need to fill in the tag generation for audio & movies. At that point, I guess it’s “what more than making it easy to include them”. My needs are pretty simple so what I have at that point is probably enough for me. If anyone else were doing something more complex, I’d be open to hearing what they needed.

You make a good point about evolution. There are already a lot of systems, but none that I felt were well-suited to the hybrid IF simulation/RPG space I want to play in and will grow Rez towards (for example I already have some support for procedural generation and want to improve that).

Who knows if it will turn into anything but it’s fun to try :smile:

Hi Daniel.

Feel free to; I appreciate the feedback.

You’re right about the demo, I threw it together really fast, and it looks like it! I’m expanding on it and will try to style it better.

I’m using Bulma as the CSS library. It’s not a library that I am very familiar with, but it was easy to include and seems pretty clean. It might be as simple as linking to an available free theme. Worth a try, anyway!

Thanks again for your thoughts.

M.

Interesting. What do you see as the distinction between IF and RPG. Are we talking combat systems or something else?

So I updated the sample cointoss game and sprinkled a few Bulma CSS classes.

@game begin
  name: "Test Game"
  IFID: "D3C31250-53B4-11ED-9A26-3AF9D3B0DD88"
  archive_format: 1
  initial_scene: #intro
  links: [
    "https://jenil.github.io/bulmaswatch/journal/bulmaswatch.min.css"
    "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
  ]
  layout: """
  {{{scene}}}
  """

  @scene intro begin
    initial_card: #get_name
    layout_mode: :single
    layout: """
    <div class="container">
    <h1 class="title">SuperCoinToss</h1>
    <h2 class="subtitle">A game written with Rez</h2>
    {{{content}}}
    </div>
    """
  end

  @card get_name begin
    content: """
    Before you play:

    <form class="form" name="name_form" rez-live>
      <div class="field">
        <label class="label" for="name">Name</label>
        <div class="control has-icons-left has-icons-right">
          <input class="input is-success" type="text" name="name" placeholder="What is your name?"></input>
          <span class="icon is-small is-left"><i class="fas fa-user"></i></span>
          <span class="icon is-small is-right"><i class="fas fa-check"></i></span>
        </div>
      </div>
      <div class="field">
        <label class="field" for="target_score">Target Score</label>
        <div class="control">
          <select class="select" name="target_score">
            <option value="5">5</option>
            <option value="10">10</option>
            <option value="15">15</option>
            <option value="20">20</option>
          </select>
        </div>
      </div>
    </form>
    """
    on_name_form: (card, event) => {
      const name_field = event.form.elements["name"];
      const name = name_field.value;

      const score_field = event.form.elements["target_score"];
      const score = score_field.value;

      if(name != "") {
        const player = card.$("player");
        player.setAttribute("name", name);
        player.setAttribute("target_score", score);
        card.game.setCurrentScene("play_game");
      } else {
        name_field.className = "important";
      }
    }
  end

  @actor player begin
    score: 0
  end

  @scene play_game begin
    initial_card: #play_round
    blocks: [#sidebar]
    layout_mode: :single

    layout: """
    <div class="container">
      <h1 class="title">SuperCoinToss</h1>
      <h2 class="subtitle">A game written with Rez</h2>
      <div class="columns">
        <div class="column is-one-quarter">{{{sidebar}}}</div>
        <div class="column">{{{content}}}</div>
      </div>
    </div>
    """
  end

  @card sidebar begin
    bindings: {player: "player"}
    content: """
    <p class="title is-3">{{$ player "name"}}</p>
    <p class="subtitle is-5">Score: {{$ player "score"}}</p>
    """
  end

  @card play_round begin
    on_start: (card, event) => {
      card.setAttribute("coin", coin_flip());
    }
    content: """
    Do you [[Choose heads]] or [[Choose tails]]?
    """
  end

  @alias result_card = card # begin
    bindings: {player: "player"}
    content: """
    {{$ card "response"}}
    [[Play again|play_round]]
    """
  end

  @result_card choose_heads begin
    on_start: (card, event) => {
      const flip = card.$("play_round").getAttribute("coin");
      won_or_lost(card, flip == "heads");
    }
  end

  @result_card choose_tails begin
    on_start: (card, event) => {
      const flip = card.$("play_round").getAttribute("coin");
      won_or_lost(card, flip == "tails");
    }
  end

  @card winner begin
    content: """
    You are a winner!
    """
  end

  @card loser begin
    content: """
    Sorry, you lost!
    """
  end

  @script begin
    function won_or_lost(card, winner) {
      const player = card.$("player");
      const game = card.game;

      if(winner) {
        card.setAttribute("response", "Congratulations");
        player.incAttribute("score", 2);
        if(player.getAttributeValue("score") >= player.getAttributeValue("target_score")) {
          game.getCurrentScene().playCardWithId("winner");
        }
      } else {
        card.setAttribute("response", "Bad luck");
        player.decAttribute("score");
        if(player.getAttributeValue("score") <= -player.getAttributeValue("target_score")) {
          game.getCurrentScene().playCardWithId("loser");
        }
      }
    }

    function coin_flip() {
      return (Math.random() < 0.5) ? "heads" : "tails";
    }
  end

  @style begin
  .important {
    border-style:solid;
    border-width:2px;
    border-color:red;
  }
  end
end

Ah, that was a bit more throwaway than a distinction that would hold up in a “theory of games” sense. You’re right that systems are a part of it (also the role of narrative and puzzles). It would take me a little longer than I have right now to articulate what I am thinking in a meaningful way.

Cool, I actually think that’s a major improvement since people could start with your example and then just work on implementation until they were ready to pretty it up. Completely unstyled I feel like I’d be distracted by that immediately.

1 Like

I just realised that as a side effect of the library I wrote to create “logical files” (to handle includes), you can do this with string content. So you could re-write:

layout: """
<div class="container">
  <h1 class="title">SuperCoinToss</h1>
  <h2 class="subtitle">A game written with Rez</h2>
  <div class="columns">
    <div class="column is-one-quarter">{{{sidebar}}}</div>
    <div class="column">{{{content}}}</div>
  </div>
</div>
"""
layout: """
%(play_game_layout.html)
"""

And then, move the string into a file play_game_layout.html, and it continues to work. I’d never considered moving HTML/Markdown out of the main file.

The upside is that it looks a little cleaner, and the HTML can be syntax appropriately highlighted by your editor. The downside is that you can’t just see it, you have to open another file (but this is the case for any include-type macro).

Is it better? I’m not sure. But it is an option.

2 Likes

Cool! It’s neat that it’s possible. I would use this.

I liked this approach, so I have extended the language to read the value of attributes from a file. Currently, it supports reading strings from .txt, .html, and .md files and Javascript arrow functions from .js files. The following is now legal:

layout: <<<intro_layout.html>>>

and:

on_start: <<<start_callback.js>>>

In a longer game, you’re going to split it up and use the %(file) include macro anyway, so this becomes a convenient shortcut for particular kinds of value that might be more uncomfortable to write inline.

I was re-reading your comment, and I think this is an intriguing & provocative statement. But is it true? When you say “most people” do this, it sounds plausible, but I wonder what you base it upon.

If it is true, it seems to point to something problematic. I love Minecraft, but I’m not sure that sitting down with Java & LWJGL is necessarily a great way to approach building a game. Silly example, but hopefully, it illustrates the point.

If we acknowledge that there is a lot of room for different approaches to the problem, perhaps a decision tree to lead potential authors to the best tool for them is warranted. For example, a prospective author with little affinity for programming will likely have a rough time with Rez, no matter how much they liked a game built upon it.

On that note, I recently implemented behaviour trees as an alternative to scripting behaviour. I wonder if a writer with a bit of logical thinking could build behaviour with a more technically experienced partner creating condition & query tasks that they need (these are implemented in Javascript).

Anyway, thanks again for your thoughts.

I think you’re comparing Minecraft to the wrong things. This isn’t Java vs. Unity/Unreal. You’re talking about putting a new language into the ecosystem: if you had a choice between Java/Zig/Io/Factor, why would you choose anything but Java? If someone else has gone before, you know it’s actually possible to make Minecraft in this language, and it’s not just a toy project where you’ll get halfway in and realize it just doesn’t work.

And I think that goes double for a community where a large majority are not programmers: you want to know that writers like you can learn this, and it’s a lot harder for you to learn/evaluate a new tool. Why wouldn’t you just stick to the tool you know and that lots of other people use? You know it can do all kinds of things and you know you can get help if you get stuck.

“Writer with a more technically experienced partner” does happen but it seems to be a pretty rare situation. If you assume anything other than “writer with little affinity for programming,” you’re aiming at a niche within an already small niche…

2 Likes

I had a feeling the Minecraft example would turn out to be a mistake, ah well.

What I was trying to get at is, if Dan is correct, that the tool one author uses to create something isn’t necessarily the tool another author should use, even if they like the product.

Your second point, about community and a prospective author asking themselves, “Can I get help with this?” feels on point. Of course, any new thing can struggle here, hence Dan’s point about pump priming.

I think you’re right that I am aiming at a niche within a small niche. It’s possible even that I am aimed at a niche of 1. I could live with that, although I would be disappointed. What tool creator doesn’t want to see his or her creation be helpful to others?

Thanks for the comment.

I misinterpreted your comment, Dan; you are likely correct: they start by asking themselves, “How did this get made?” and go from there.

1 Like

Ah, I see. That still feels like a programmer-ish rather than a writerly way to look at it. I don’t think “should use” comes into it. For non-technical people, learning a new tool is often a BIG investment and they’re used to computers requiring them to manually do things that could be automated, so that’s less of a big deal, and they’re asking “can my current tool be made to do this?” and not “is this the ‘right’ tool for the job?” and in fact a lot of people associate that whole mindset with jerks online berating them for using the “wrong” tool instead of just giving the quick easy answer to the problem in front of them.

Anyway. Rez looks promising, but uptake is slow. Do it for you. Even if you put a lot of time into making and sharing stories in it, writing documentation and tutorials, running game jams, etc., you should still expect it’s going to take at least 2-4 years to get much traction…

In my experience, this is very common in online discussions of music and video software. One of my favorite things about this forum is that in these circumstances – usually – a questioner is given a “gentle” suggestion that maybe this or that isn’t the best tool (or method) – almost immediately followed by an example of how to do it anyway.

2 Likes