I was thinking about what it could be like to implement a Glk (GlkOte? GlkOte only?) extension that could support displaying a map provided by the interpreter, e.g. ADRIFT.
Automapping is a pretty weird topic with a lot of edge cases; I’m not surprised nobody’s tried to take it on before.
I started imagining a Glk extension shaped like this:
#define mapimage_SVG 1 /* UTF-8 SVG; root must define a viewBox or width/height */
#define mapimage_PNG 2
#define mapimage_JPEG 3
#define mapflag_None 0x00000000
#define mapflag_HasFocus 0x00000001 /* focus_* arguments are meaningful */
#define mapflag_SuggestShow 0x00000002 /* soft hint: prefer making the map visible */
#define mapflag_UserRequestedShow 0x00000004 /* the user just asked to display the map */
glui32 glk_map_present(
glui32 format, /* mapimage_* */
const unsigned char *data, /* document bytes */
glui32 len,
glui32 flags, /* mapflag_* */
glsi32 focusleft,
glsi32 focustop,
glui32 focuswidth,
glui32 focusheight);
void glk_map_clear(void);
glk_map_present() would create or replaces the current “map document.”
- Returns 1 on success, 0 on failure (unsupported format, corrupt data, refused document, etc.).
- On return (success or failure), the library retains its own copy of the document; the program may free
dataimmediately. - The runner should provide some UI for panning and zooming the map, as well as hiding/showing the map, but this isn’t required. (Maybe there’d be testable gestalts for those features…? That way the terp/author could say “if this Glk runner doesn’t support panning and zooming, don’t show the map at all”)
- A successful
glk_map_presentdoes not require the map to become visible. If the player previously hid the map, it generally stays hidden, but the latent document updates.mapflag_SuggestShowis a hint that the library may show it (e.g. first map of the session, or after a major update).mapflag_UserRequestedShowsays that the user just requested to show the map (we have to take the terp’s word for it, but perhaps the user just typedmaporshow map, or selected “Show Map” off of an in-game menu), so the runner should re-show the map after the user has hidden it.
- If
mapflag_HasFocusis set, the focus rectangle is the region the library should try to keep viewable after present (and typically after player “recenter” actions). If focus is omitted, the library may keep the current pan/zoom or fit the whole document — implementation-defined. - Just one map is allowed at a time. (Right??)
glk_map_clear() destroys the map document. The library should remove map chrome (or disable map UI). It is legal when no map exists.
Refocus without re-sending the document
void glk_map_set_focus(
glsi32 focusleft,
glsi32 focustop,
glui32 focuswidth,
glui32 focusheight);
void glk_map_clear_focus(void);
Present an image resource from a Blorb?
glui32 glk_map_present_image(
glui32 image, /* Blorb pict id, as in glk_image_draw */
glui32 flags,
glsi32 focusleft,
glsi32 focustop,
glui32 focuswidth,
glui32 focusheight);
Blorbs don’t support SVG (yet, maybe ever). SVG is an enormously complicated standard, with zillions of optional features, some of which can do I/O.
But for something like Counterfeit Monkey, where the map is a handrolled PNG, this feels like a nice convenience.
If the map can be a rasterized image resource, you’ll probably want to rasterize map overlays, too
“Map overlays” are layered images that you can stack on top of a map (and on top of each other).
SVGs don’t need a separate API for overlays (because you can just put the overlay content directly into the SVG; SVGs are just XML text and easy to merge).
But if you want to draw a “you are here” symbol on top of a rasterized map, or if you want to change the background color of one room in the map, you’ll probably need an API like this:
overlayid_t glk_map_overlay(
glui32 image, /* Blorb pict id, as in glk_image_draw */
glsi32 left,
glsi32 top,
glui32 width,
glui32 height,
glui32 zindex);
glui32 glk_map_overlay_move(
overlayid_t overlay,
glsi32 left,
glsi32 top,
glui32 width,
glui32 height,
glui32 zindex);
glui32 glk_map_overlay_clear(overlayid_t overlay);
glui32 glk_map_overlay_clear_all(void);
The map itself would have zindex 0; overlays with higher zindex would render on top of (obscuring) overlays with lower zindex.
Out of scope?
- Multiple maps
- Clickable maps
What would the Glk runner do, actually?
For comparison
- Counterfeit Monkey: Managing its map has been a huge source of bugs over the years.
- As of v11, Counterfeit Monkey starts by disabling its map, allowing users to reveal the map as a graphics window that occupies the side pane with
map on. If you do that on mobile, you’re going to have a bad time, but you’ll probably be able to figure out how tomap offto make it go away. - Alternately, if you just want to peek at the map, you can type
map, which displays in the text buffer as a full-screen image. - Each room has its own pre-rendered map, with the “you are here” symbol burned into the image. When showing the map, the UI just shows the current room’s pre-rendered image. (This feels suboptimal. Separate map overlay layers would work much, much better.)
- As of v11, Counterfeit Monkey starts by disabling its map, allowing users to reveal the map as a graphics window that occupies the side pane with
- Hadean Lands: Custom UI everywhere for Hadean Lands. I don’t think any of the source of that is publicly available…?
- On desktop OSes, it starts by opening multiple OS windows, one for the text buffer, one for the map, and one for the “journal” that includes rituals, formulas, and facts. The map is pre-rastered as a PNG, with labels as overlays that you can hide/show with a “Labels” button in the map menu, and an animated “you are here” symbol, a star. There’s a “Flash Star” button that enables/disables flashing.
- On iOS, the game launches in a tabbed view, with these tabs: Game (the text buffer), Journal, Map, Help, Settings.
- ADRIFT: (This is what originally got me thinking about this problem.) In ADRIFT, authors can declare a map of rooms and exits, each with visibilities. You can make the whole map visible at game start, or reveal the map room-by-room as you explore. From the user’s perspective, it feels like an “automap”, but it’s not trying to automatically parse the transcript; it’s revealing more and more of the author’s hand-coded map model.
- ADRIFT also lets you click on rooms of the map; the game runs Dijkstra’s algorithm to find the shortest path from your location to the destination, and automatically emits “go north.” “go west.” etc. commands to get you there.
- The official ADRIFT-5 runner is only available for Windows. ADRIFT’s runner has a fancy dockable UI. You can drag and drop the map window (or other “named windows”) to the top, bottom, right, and left of the screen; you can pop them out and turn them into floating windows that you can reposition wherever you like.
- FrankenDrift is available on other platforms; it makes a separate OS window available for the map, which the user can position manually. (On macOS, the map window spawns underneath the text buffer, making it difficult to discover, but it is there.) FrankenDrift doesn’t attempt to render a map on Glk.
Terp-rendered SVG maps
Some interpreters support author-provided automaps, like ADRIFT.
In that case, the terp would render the map as an SVG string and present it via glk_map_present().
As the map updates (e.g. moving the “you are here” marker), the terp would call glk_map_present() on each turn, presenting (representing) the entire SVG string each time the map updates. (SVG strings are quite short.)
Color recommendation for terp-rendered SVG maps: Measure the Normal TextColor/BackColor with glk_style_measure, and use those colors in the generated SVG (for now?)
glk_style_measure can report on the foreground text color and background color of the “Normal” style for the transcript window. If the user has opted to override stylehints that the terp has provided, glk_style_measure will report that, giving you a reasonable background color and foreground color for rendering.
If glk_style_measure returns false, use a default color scheme. For example, RemGlk interpreters (including Parchment and Lectrote) don’t implement glk_style_measure at all, returning FALSE in all cases. (glk_style_measure would require an asynchronous remote procedure call, asyncifying the function.)
I note that stylehints have been kinda “deprecated” for years, partially replaced by the garglk_set_zcolors Glk extension, and hopefully soon to be replaced by the CSS Glk extension.
But, as I write this, there is no other API proposed to access the normal text colors, so glk_style_measure is all we have.
My guesses as to what the UI would look like
I’m imagining that Glk runners that support mapping would have different UI for large/small screens (and that the runners would be the best decision makers for how/when to do that).
- Parchment/webUI runners would probably display the map in a side pane with a close button if the window is “wide enough.” If the window is too narrow, the map would be hidden by default. If there’s an on-screen menu (a hamburger menu, or a toolbar), a “Show Map” button could appear there if the map isn’t visible. (And, I think webUI runners should have a menu, at least a hamburger menu, with buttons to save, restore, restart, adjust settings, and get help.)
- Desktop runner apps (Gargoyle, Spatterlight, Lectrote) could open the map in an OS window, which the user could reposition. ADRIFT’s runner has a fancy dockable UI, which feels like overkill to me, but it works, and maybe that’s “best” for power users. IMO non-power users struggle to understand it. Grandpa’s Ranch (a beginner-friendly ADRIFT game intended for the Text Adventure Literacy Jam) had to include a bunch of in-game documentation trying to explain to newbies how ADRIFT’s layout system works, which suggests to me that ADRIFT’s layout system is the wrong approach, even for a desktop-only IF interpreter.
- When closing the map, perhaps it would make sense to print a message explaining how to re-open the map, e.g. with a “View → Map” menu, or by typing a
MAPcommand or something.
- When closing the map, perhaps it would make sense to print a message explaining how to re-open the map, e.g. with a “View → Map” menu, or by typing a
- Mobile apps have been pretty creative about menus.
- I mentioned Hadean Lands’s tabs; that looks pretty good.
- A hamburger menu would work, too.
- iOS Frotz has a little menu “book” in the prompt; you can tap on it to get a bunch of commands to auto-type. Adding “map” in there would be nice.
- Check out Fabularium’s custom-keyboard menu. I notice the M key doesn’t have anything on it, which would be perfect for showing the map!

What do you think?
Is this anything? If I filed PRs on Parchment, Gargoyle, Lectrote, etc. to support this, would you consider merging those PRs, or just close them without merging?





