Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Snowman, an experimental alternate story format

Leon made a really good point on Twitter recently, that there is a whole stack of languages you need to learn in order to fully master Twine. I hope I'm not paraphrasing him incorrectly, but I think his interest is in building bridges to CSS and JS that people who are comfortable with Twine syntax would find clear.

I wanted to try working on the problem from the opposite side, to remove the Twine-specific parts of the stack. Snowman gives you as raw an interface to JS/CSS as possible, so that if you already know how these work, you can apply that knowledge without having to learn much about Twine. Here's how Snowman differs from the usual order of business:
  • It uses Markdown syntax for formatting, not TiddlyWiki.
  • No macros. Instead, it evaluates anything inside <% %> as Javascript, and uses <%= %> as a shortcut for printing the result of some JavaScript. Some examples:
    • <<set $candies = 2>>
      becomes
      &lt;% state.candies = 2 %&gt;<br /> </li><br /><li><code>You have &lt;&lt;print $candies&gt;&gt; in your pocket.
      becomes
      You have &lt;%= state.candies %&gt; in your pocket.
    • &lt;&lt;if $candies gt 1&gt;&gt;<br />&nbsp; &nbsp; &lt;&lt;set $candies--&gt;&gt;<br />&nbsp; &nbsp; You gobble a candy down. &lt;&lt;print $candies&gt;&gt; left!<br />&lt;&lt;endif&gt;&gt;
      becomes
      &lt;%<br />if (state.candies &gt; 1)<br />{<br />&nbsp; &nbsp; state.candies--;<br />&nbsp; &nbsp; passage.write(&#039;You gobble a candy down. &#039; + state.candies + &#039; left!&#039;);<br />};<br />%&gt;<br />
  • It includes jQuery and triggers custom events such as showpassage and hidepassage as the user takes actions, so that you can add your own behavior.
  • It sets some very basic CSS styles as a baseline but does not add any UI beyond the passage that's onscreen.
  • It doesn't add an entry to the browser history for every passage clicked. Instead, you write &lt;% story.checkpoint() %&gt; to add a history entry, and &lt;% story.save() %&gt; to put a permalink to the current story state in the user's address bar. (I shamelessly stole how to do this from Leon's Harlowe source code, e.g. the Twine 2 runtime.)
  • Speaking of stealing from Harlowe, it also supports [[Displayed text-&gt;destination]] link syntax.
So this isn't meant for everybody, and is obviously a first attempt... but I'm curious what people think. The repository has instructions on how to install it in Twine 1.4.

Comments

  • This is a great idea (Twine for Grown-ups?!?), and if I was coming to Twine now I would definitely use it. Having had a couple of months to get to know <<macros>>, I am not so sure if I will, but it is interesting to play around.

    In that spirit, I set up a page like this:
    <% state.name = 'Fred' %>

    <% alert(state.name) %>

    Hello <%= state.name %>

    [[Second]]
    ... and it said "Hello undefined". The alert had the value right, and it was right on the second page too, but not here. Does it evaluate scripts in a funny order? I am using Twine 1.4.2 on Firefox/Win7 by the way.

    Edited to add:

    I also had a go at converting a game I have on the go. It has a character creation page, and I was wondering how to do text boxes and radio buttons. I tried doing that in raw HTML, but it just displays the HTML code, not the controls.

    Also, it does not seem to support setting values in links:
    [[Begin][state.fullname = document.getElementById("fullname");state.sex = document.getElementById("sex");state.charclass = document.getElementById("charclass")]]
    It tries to find a link to a passage with the name Begin][state.fullname = document.getElementById("fullname");state.sex = document.getElementById("sex");state.charclass = document.getElementById("charclass").

    Perhaps I am assuming this is a fully working system, when it is a work in progress?
  • Thanks for trying it! I would say this isn't done, really... I wanted to put it out there and see what feedback people had. I don't think I'm going to make huge changes to the overall design, mainly because the whole point of the design is to be minimal.

    The HTML and the "Hello undefined" things are both bugs -- I logged them at https://bitbucket.org/klembot/snowman-1.4/issues. Feel free to add more!

    There's isn't exactly functionality for adding links that just execute JavaScript -- though in this scenario, wouldn't you want to run some JS and then go to a different passage? But I can see that it would be useful regardless. You could in theory write:

    [Begin->javascript:state.fullname = document.getElementById("fullname");state.sex = document.getElementById("sex");state.charclass = document.getElementById("charclass")]
    But that's kind of a mess to read, with all the code stuck together on one line. I considered some alternatives -- I'm not sure which syntax I like better yet.

    <%
    passage.writeLink('Begin', function()
    {
    state.fullname = $("#fullname").val();
    state.sex = $("#sex").val();
    state.charclass = $("#charclass").val();
    story.show('Trailhead');
    });
    %>
    or

    <%
    passage.appendElement($('a')
    .text('Begin')
    .click(function()
    {
    state.fullname = $("#fullname").val();
    state.sex = $("#sex").val();
    state.charclass = $("#charclass").val();
    story.show('Trailhead');
    }));
    %>
    I lean towards the latter because it's a lot more flexible -- e.g. it's easy to add custom CSS classes or other kinds of event handlers besides just click.

    (In both cases I rewrote your code a little bit to take advantage of jQuery.)
  • I like the idea of doing work in this area, but I don't feel like this implementation does enough to address the "too many languages" problem.

    The five languages Leon identified are:

    TiddlyWiki text formatting
    HTML tags
    CSS inside HTML tags and stylesheets
    macro tags
    Javascript functions and data types inside macro tags

    Snowman takes a step in the right direction by eliminating macro tags, but still leaves four languages on the stack, replacing TiddlyWiki with a Markdown variant. Markdown is probably an improvement upon TiddlyWiki, but if the plan was to reduce the number of languages, Markdown is not the way to do it.

    In his statement of the philosophy of Markdown, Gruber wrote, "The idea is not to create a syntax that makes it easier to insert HTML tags. In my opinion, HTML tags are already easy to insert. The idea for Markdown is to make it easy to read, write, and edit prose. HTML is a publishing format; Markdown is a writing format. Thus, Markdowns formatting syntax only addresses issues that can be conveyed in plain text."

    But stories in Twine are more hypertext than prose, and Markdown's weakest point is how painful it is to create hyperlinks. Hence the need to add the [[Displayed text->destination]] syntax.

    Why not use raw HTML as the language? IMO, there are two core problems with raw HTML.

    1) Raw HTML strips whitespace, forcing the user to use hideous <p> tags. But a dash of <style>body { white-space: pre; }</style> will clear that up. If the user doesn't want that effect, a little CSS will clear it up.

    2) HTML links can be verbose. But they're not that bad if you omit quotes, which is now specified behavior in HTML5. <a href=destination>Displayed text</a> is really not that bad.

    And HTML already includes a <script> convention for including inline JS, which is only a little longer than <% %> and has the benefit of being totally standard. Don't want to run the script right away? Set the type to something non-standard and switch it back in JS as the user navigates to the node. <script type=x></script>

    Upcoming features of HTML+JS include a templating language, which can make this type of development even easier. And Traceur can be used to backport those features to today's browsers.

    WDYT?
  • My personal experience of late has been with Sugarcube, and there's one feature that I tend to abuse massively in my work with it - the widget macro. It allows you to create a shorthand for anything within the <<widget X>><</widget>> bounds.

    Then you just call it with the name you've given the widget, which can be as short and/or mnemonically easy as you can think of. I don't think I can give a terribly good explanation here, so I suggest reading about it here. Something of a extended version of this is what I'd like to see most in the user-friendliness direction.
  • Actually, for a novice who isn't into Javascript, CSS and HTML - like most authors. The current (1.4.1 vanilla) system is pretty good.  Lets me edit text, make links, format text a little use variables when I'm ready to and maybe insert a macro or two.

    What I'd add to it would be a point and click style sheet constructor (so I just picked what I wanted in the stylesheet from some tabbed menus and never had to edit the CSS at all).  Mostly what I'm going to want is the ability to change text color and size and background colour - and maybe supply an image. 

    Yes, you can do heaps of flash tricks with it, but most of us just want something simple that works - which 1.4.1 is.  Please don't break it in the name of fitting a few more tricks into the box.

    IMHO, making the standard anything more complicated that to current is a move in the wrong direction.  If you want a better editor, make it WYSIWIG, not cryptic html or CSS or javascript or anything else.  It's job is to hide the complexity, not to expose it.
  • I don't think this is a proposed change to the standard, Mykael, hence the 'Snowman' name. I can see the appeal for some, but standard Twine for us coding n00bs isn't going anywhere. The OP makes it pretty clear that this isn't for everyone. ;)
  • dfabulich wrote:

    1) Raw HTML strips whitespace, forcing the user to use hideous <p> tags. But a dash of <style>body { white-space: pre; }</style> will clear that up. If the user doesn't want that effect, a little CSS will clear it up.


    Hadn't considered that -- I think though that if we did that, we'd lose word-wrapping. Here's a fiddle I used to check.

    dfabulich wrote:

    2) HTML links can be verbose. But they're not that bad if you omit quotes, which is now specified behavior in HTML5. <a href=destination>Displayed text</a> is really not that bad.


    For a decent number of cases, though, you'd be writing &lt;a href=Open the door&gt;Open the door&lt;/a&gt; which seems like busywork for an author.

    dfabulich wrote:

    And HTML already includes a <script> convention for including inline JS, which is only a little longer than <% %> and has the benefit of being totally standard. Don't want to run the script right away? Set the type to something non-standard and switch it back in JS as the user navigates to the node. <script type=x></script>


    Using &lt;script&gt;...&lt;/script&gt; seems like a reasonable idea assuming the runtime would be able to change the script type before the browser tried to execute it. Only downside is that it seems useful to be able to write You have &lt;%= state.candies %&gt; instead of You have &lt;script&gt;passage.write(state.candies)&lt;/script&gt;.

    dfabulich wrote:

    Upcoming features of HTML+JS include a templating language, which can make this type of development even easier. And Traceur can be used to backport those features to today's browsers.


    I haven't seen anything about HTML5 templating-- could you point me to some reading?

    I think overall a lot of this comes down to what Larry Wall means by Huffman encoding... things you need to write a lot should take as few characters as possible without becoming unreadable. (Whether Perl passes that second test is a whole other story...) The point of using Markdown for me is conciseness. That said, you can write HTML in Markdown and it just works, is my understanding, so it's there as an option.

    Trip wrote:

    My personal experience of late has been with Sugarcube, and there's one feature that I tend to abuse massively in my work with it - the widget macro. It allows you to create a shorthand for anything within the <<widget X>><</widget>> bounds.


    The Snowman idiom for the SugarCube example I found in the docs would be:

    <%
    function he()
    {
    if (state.pcSex == 'male')
    return 'he';
    else if (state.pcSex == 'female')
    return 'she';
    else
    return 'it';
    }
    %>

    "Are you sure <%= he() %> can be trusted?"
    Which to me is a tossup in terms of readability -- fewer pairs of <<>>s, at least.

    mykael wrote:

    IMHO, making the standard anything more complicated that to current is a move in the wrong direction.  If you want a better editor, make it WYSIWIG, not cryptic html or CSS or javascript or anything else.  It's job is to hide the complexity, not to expose it.


    Yep, I see this always existing as an alternate to the usual way of doing things.
  • klembot wrote:

    dfabulich wrote:

    1) Raw HTML strips whitespace, forcing the user to use hideous <p> tags. But a dash of <style>body { white-space: pre; }</style> will clear that up. If the user doesn't want that effect, a little CSS will clear it up.


    Hadn't considered that -- I think though that if we did that, we'd lose word-wrapping. Here's a fiddle I used to check.


    Use white-space: pre-wrap instead.

    klembot wrote:

    dfabulich wrote:

    2) HTML links can be verbose. But they're not that bad if you omit quotes, which is now specified behavior in HTML5. <a href=destination>Displayed text</a> is really not that bad.


    For a decent number of cases, though, you'd be writing &lt;a href=Open the door&gt;Open the door&lt;/a&gt; which seems like busywork for an author.


    Well, some JS is required regardless to avoid navigating to another page, so I'd be fine with <a>Open the door</a> automatically doing the right thing.

    klembot wrote:

    Using &lt;script&gt;...&lt;/script&gt; seems like a reasonable idea assuming the runtime would be able to change the script type before the browser tried to execute it. Only downside is that it seems useful to be able to write You have &lt;%= state.candies %&gt; instead of You have &lt;script&gt;passage.write(state.candies)&lt;/script&gt;.


    Yeah, that's really the sweet spot for templating.

    klembot wrote:

    I haven't seen anything about HTML5 templating-- could you point me to some reading?


    http://www.html5rocks.com/en/tutorials/webcomponents/template/
    http://tc39wiki.calculist.org/es6/template-strings/
    https://github.com/google/traceur-compiler
  • Just a quick update that I've fixed the bugs Pixie mentioned and have updated downloads. Still mulling over architectural changes...
Sign In or Register to comment.