Glk stylesheets: the Plan

Two days before the end of the month, even.

I have posted three documents:

There is a whole lot of work involved in this plan, so you’re not going to start using it next week or anything. But I am reasonably convinced that this is the roadmap. It’s consistent with the last discussion I had with Graham on the subject.

Comments:

  • If glk_end_style_name()/glk_end_style() generate run time errors then will they get used? It would be far too risky for the library to call them, because the user may have forgotten to end a style they added to the stack. I’d like to suggest the following API functions instead:[list][*]glk_inspect_style(): returns the style at the top of the stack
  • glk_end_style_name()/glk_end_style(): these functions would instead pop styles from the stack until the given style is popped. The whole stack could be emptied. No errors would be generated
    [/:m]
    [
    ]Part of me wants to say that the generated HTML shouldn’t have para_ and span_ class names as style sheets could have div.style and span.style instead. (As well as a generic .style.) But then that would lock implementations into using particular elements, which I don’t like the idea of (I’d like to use s I think.)[/:m]
    [
    ]Can you explain some of the use cases for HTML windows/frames?[/:m]
    [
    ]Instead of html windows loading resources from the blorb, can they just use inline styles and scripts, and use data: for images?[/:m]
    [
    ]Instead of GlkEntry/GlkEvent, what about just using postMessage()? Support is good: caniuse.com/x-doc-messaging[/*:m][/list:u]

Neat-o.

I think that’s wise, for Glk not to check strict usage and let a higher level do, or not do, it. But if it does take this hands-off approach, is printing a run-time message to the player appropriate for confused usage? Maybe Glk should just tell the calling library instead, and let the library decide whether to bother the player.

What does Glk do in cases of the style stack overflowing or underflowing? I think underflow could be silently ignored, but overflow…?

This confuses me. If I don’t use paragraph styles, but just stick a span style mid-paragraph, the above wording implies than when I end the span, the rest of the paragraph will still have that style – it won’t turn off until the end of the paragraph even though I told it to end at the end of the span. Do I misunderstand something here?

Other parts of I7 use the form “a number based rulebook”, so I’d be somewhat surprised by anything but “header based text style”. A minor point, I know. (And please let us not capitalize non-proper names mid-sentence! “header”, not “Header”! It’s a pet peeve of mine when I read others’ I7 code.)

I feel slashes are un-Inform-like – witness [bracket] and [close bracket] – but, ::shrug::

Yes please!

Also: is Glk married to Javascript, disallowing Javascript’s competitors?

That’s a fair point.

I want errors to be visible to the author during testing. But they don’t have to be fatal errors for that, and the interpreter really can only throw fatal errors. At the same time, I don’t want game code to be in a paranoid loop of constantly interrogating the style state in order to do anything. That’s a waste of time.

I like Ron’s suggestion that the call should return an error value. That way, the game can display a warning when in debug mode only.

I separated them out because, in some cases, double-applying a CSS attribute is bad.

If you have “Header” as the current style, then (following the rules as I’ve written them) you’ll get span_Header spans inside para_Header divs. That’s not a problem with my sample stylesheet. But if these had the same class name (“Header”), then a “.Header {font-size: 1.4em;}” declaration would apply twice, and the font size would be multiplied by 1.96!

The examples I gave are supposed to be definitive for elements as well as classes. So yes, I’m already locking the implementing into using

and .

I’ve got a guy in email who’s been begging me to permit panoramic photo display in a Glulx window. I don’t know how that works (it’s probably a Flash applet) but if he can make it work in a web browser, he should be able to make it work in a Glulx window.

More generally, it’s an out for people who are tired of writing graphics in I7 code. No offense to GLIMMR! But if I want a fancier status line, with custom fonts, gradients, some icons, and maybe a decorative border, it’s very easy to build that using HTML.

People could do that but I’d hate to require it of them. We’ll see how practical my other ideas are.

I hadn’t looked at that; I’ll read up on it. It looks designed for JS-to-JS communication, right? I also have to think about (e.g.) a MacOS app which has embedded a WebKit view and is calling from ObjC-to-JS.

Underflowing is an error, which is currently described as a fatal error, but I’ll change that to an error return value. As for overflow, there is no limit on span nesting. (If you want to run the interpreter out of memory, there are easier ways than style abuse.)

The “current paragraph style” is only applied to a paragraph when the paragraph begins. Further changes only affect what will happen to the next paragraph. I guess that’s not very clear – I’ll add some explanation.

Up to Graham. But you’re right about capitalization. I’ll change those examples.

Ask me again in a couple of years, if there are competitors by then. :confused:

I deliberately made the call name generic – “glk_script_send()” – to avoid specifying this. In theory, Glk doesn’t care what the scripting language is, as long as the game and browser agree. In practice, that means Javascript. I can imagine a future where there’s a real choice, and then somebody would have to specify a language somewhere, but we’re not there today.

No offense taken. I will be very happy to see Glimmr obsolesce when these new features are in place and widely supported! Embedding an HTML frame will allow for all kinds of stuff that you can’t do with Glulx graphics–images mixed with actual text, dynamic rotation, shadows, etc. And the ability to get input from embedded frames opens up all kinds of possibilities.

The plan looks great. Will there be a core of recommended CSS rules that interpreters that don’t use HTML for display should support? (Mostly so that game authors will know what will work widely and what will only work on web or widget interpreters.)

I noticed the call naming, but the spec has JS all over it and even called out jQuery specifically. I don’t know how agnostic Glk can be, but the spec should at least state if it’s agnostic or not, or at least where it is and isn’t, or at least its intention.

I know JS is everywhere now, but IF tech seems to have longer shelf life than many tech, so it’s not unreasonable to presume this spec will live to see a JS competitor.

I was confused too. As I read the document, it looks like:

  • There is a stack of styles.
  • A style is either a single ClassicStyleNum or a pair (ClassicStyleNum, StyleNameStr).
  • The “current paragraph style” is an alternate name for the style at the bottom of the style stack.
  • The “style of the current paragraph” is the default style used within the paragraph. The paragraph’s style is set to the “current paragraph style” the first time text is emitted after a paragraph break and cannot be changed thereafter (because the
    open tag has already been emitted).
  • Text emitted as part of a paragraph uses the style at the top of stack.
  • The style stack MUST NOT be cleared by glk_paragraph_break().

The distinction between “the current paragraph style” and “the style of the current paragraph” is a subtle one. Replacing “the current paragraph style” with “the bottommost style” or “the style at bottom of stack” might reduce the confusion.

I agree that under the break model of paragraphing (versus a model built around *glk_paragraph_begin() or *glk_paragraph_new or whatever), making glk_paragraph_break() idempotent seems sensible. If you really want a blank paragraph, then write a non-printing character or a space and break again right after.

The paragraphing model threw me off initially. I wanted to equate paragraph break to emitting the open tag for the next paragraph (something like

), so each time you call it, you would begin a new paragraph. The fine point that paragraph style is not set till you emit text after a break finally made things clear.

How could I help?

I started sketching out a task list for this yesterday, but it’s not solid yet. Let me think over that a little more.

The more I think about this plan the more I like it.

What if glk_end_style_name() returned an error code, and optionally the style as well? end_any could do the same. I agree we don’t want them to be in a paranoid loop, but end_any and set_style can probably be used most of the time. I still think it should be possible to interrogate the stack for those cases when you really need to.

As another alternative to GlkEvent, if jQuery is required, then messages could be passed to and from Glk by triggering events on the document. Requiring jQuery isn’t nice ideologically, but it makes sense practically. If people want to use another JS library then jQuery can peacefully co-exist with it. As to the jQuery API changing… well you can also have multiple versions of jQuery loaded. Something can be worked out.

vaporware raised the question of dynamic styles on ifMUD today. The example was, what if you want to vary the color of some text at runtime? With the current system, you have to pre-commit to a limited range of colors and create them appropriately:

… .Para_0000ff { color: #0000ff; } .Para_000100 { color: #000100; } …
This is a step back from what you can do with the Z-machine, where @set_colour NUM will let you dynamically switch to a given color.

But if you could set the style attribute of a span or paragraph element directly, you could simply write something like:glk_style_t *style = glk_style_new(style_Normal, NULL); glk_style_set_dynamic(style, "color: #0000ff;"); /* second arg would be NULL to clear dynamic */ glk_begin_style(style); /* GLK takes ownership of the style memory; it will later be freed with glk_style_free; a retain-count approach would make reusing style objects easier */ … glk_end_style();This uses a different approach to the style API centered around manipulating an opaque struct managed by the GLK library. This makes it easier to alter the API later by adding new getters/setters to the struct and even NOPping out old API to retract it. Since the library allocates the storage, the struct will always have defaults, even if later specs add new fields to the style. It also makes it easy for the implementation to add private fields to the struct to manage any implementation-specific information associated with the style.

How could this be expressed in IF7? One way would be to allow something like: say "[style color: #0000ff;]text[/style]" Since styles nest as a stack, it’s always unambiguous which style is being popped by [/style]. Any text following [style would be read as the value of the style attribute on the element.

It would also be nice to be able to create the style as a function of some inputs. This is similar to what Sass/Less/etc. offer over raw CSS in allowing variables and functions to generate the CSS stanzas. IF7 could allow something like:[code]to style with color (red - a number) and (green - a number) and (blue - a number):
say “color: #[hex of red][hex of green][hex of blue]”

say “[style with color 0 and 0 and 255]text[/style]”[/code]This basically amounts to expanding a phrase returning a string like a standard to say phrase, then expanding the return value of that again, so an alternative syntax (allowing more flexibility elsewhere, as well) would be:[code]to say style with color…

to say end style with color…

say “[[style with color 0 and 0 and 255]]text[[end style with color]]”[/code]

If you can convince zarf to allow arbitrary text colors via a standard Glk call, I’ll be amazed. And frankly a little bit worried.

For dynamic styles, I think the idea is that you use glk_set_style_name to start a uniquely-named style, then use glk_script_send to invoke some JavaScript that changes the presentation of that style.

So it’s possible and a bit of a nuisance, which IMO is a good thing.

I like to think of it as a step forward.

Yes.

Yes. :slight_smile:

I’ve made some updates.

I will add some wording about how JS isn’t the universe (but I haven’t done this yet).

I knocked out everything about “current paragraph style”, because it was confusing and I’m no longer positive it works with I7’s future plans. I have queried Graham on this. More when I hear from him.

I added a bit to the default recommended stylesheet:

	.BufferPara + .BufferPara {
		margin-top: 1em; /* blank lines between paragraphs */
	}

Hard to do… I mean, the first real-life will be GlkTerm, which can squeeze boldface and italic and color out of your terminal window, and that’s about all. And then there’s ClubFloyd. So I can say “I recommend you implement as much as possible!” but that’s close to meaningless.

EDIT-ADD: I should note that I set my terminal windows to not respond to color-changing codes. So don’t go assuming that’s guaranteed either :slight_smile:

I think that I will want to use a sandboxed JS interpreter for iplayif.com. I’m just not happy with the idea of allowing access to the same scope as Parchment, with its stored savefiles, and potentially in the future, a link to some server where the savefiles would be mirrored (so that you could play them on any browser.)

If I use Narcissus, then it would provide a full JS environment, but not all of the host objects would be supported. Possibly none of the DOM would be accessible, but that’s okay if we provide a jQuery-like API. It’s unpleasant, but I wonder if we should specify a subset of the jQuery API which will be supported as part of Glk. If parts of that API are removed in future jQuery versions then we could patch it. I’d be willing to put together a draft of this API subset.

I see the concern about a web terp running arbitrary game code in its own context.

One solution is “iplayif doesn’t support Javascript callouts”. (An author’s own web site, running the author’s own game, wouldn’t have this restriction.) But it would be nice to not have to go that far, obviously. I like the idea of using Narcissus. (Footnote for onlookers: this is a Javascript engine written in Javascript.)

I don’t think we yet have to go so far as to write a formal specification for the Javascript environment. If you write up a description of what a Narcissus environment will look like, that should be enough for now. It can be firmed up when there’s working interpreter code to test with.

My suggestion is that the interpreter should restrict JavaScript calls to one namespace. The game could call for example parchment.whatever() but not whatever() directly. That way the server that hosts the interpreter can install only libraries that are known to be safe.

I’ll have a more formal proposal coming soon.

Can the interpreter do that?