The Web UI

Starting in TADS 3.1, you can choose between the traditional TADS user interface or the new Web UI. In the traditional UI, the user installs a TADS interpreter on her machine, and the interpreter displays the user interface using the native features of the operating system - opening a window on the Mac, for example, or writing to the terminal window on Unix. With the Web UI, the user interface isn't part of the TADS interpreter at all, but instead runs in a standard Web browser. The game still runs in the TADS interpreter, but the interpreter doesn't show any UI windows; instead, the game sends everything to the Web browser for display, via a network connection.

The Web UI configuration offers several big new capabilities beyond what's possible with the traditional TADS user interface:

Choosing between the regular UI and the Web UI

The Web UI is a whole separate output layer from the traditional user interface, with its own set of functions. This is good news and bad news.

The good news is that the Web UI gives you vastly more control and power than the traditional console UI offers. For one thing, all of the networking features are directly available - they're not hidden inside the interpreter, but are readily accessible and controllable from your program. For another, you have direct access to all of the browser-side coding: you can write your own HTML, CSS, Javascript, and AJAX code to run in the browser, so you can customize virtually every aspect of the user interface. There's absolutely nothing about the Web UI that's built into the interpreter; everything that's predefined is simply part of the library, so it's readily accessible and customizable. Your game's UI can do anything that a Web site can do - drag-and-drop, animation, dynamic pop-up lists, layered objects, menus, and on and on.

The bad news is that you must choose in advance whether your game will use the Web UI or the traditional UI. If you stick to the basic command-line user interface, the only difference is in compiler options, so you can actually compile the same game both ways - so you'd have a single set of source files, but you'd compile it twice, once into a .t3 file for conventional play, and again into a separate .t3 for Web play. On the other hand, if you decide to take advantage of the more advanced features of the conventional UI (such as sound playback or the Banner API), or if you want to customize the Javascript front end of the Web UI, your game will be tied to the UI that you choose.

If you have an existing game that you created with a previous TADS 3 version, you can port it to the Web UI. If you were careful to use only Adv3 functions for input and output, rather than calling built-in interpreter functions directly, porting your game to the Web UI should be a simple matter of recompiling with the Web UI compiler settings. If you made use of more advanced UI features, though, porting requires somewhat more work:

Creating a new Web UI game from scratch

The first step in creating a Web UI game is to set up your build instructions (your project's .t3m file) to include the networking functions and the Web UI version of the Adv3 library.

If you're using Workbench on Windows: Select the Create New Project command. The "wizard" dialog will ask you which type of user interface to use; select the "Web UI" button.

Note that the UI option only appears if you use the Adv3 library - that is, either the "Introductory" or "Advanced" template. If you choose a custom template, or the "Plain T3" (no library) option, the UI option doesn't apply, so you'll have to follow the instructions below for manual project creation.

If you're creating your project file manually: Follow the standard procedure for creating a .t3m file for a regular Adv3 game. Once you've set up the basic .t3m file, follow the instructions below for changing a .t3m file from a conventional game to the Web UI.

Porting an existing game

To port an existing game based on the traditional console user interface (including HTML TADS games), the first step is to switch to the Web UI libraries. This requires a few changes to your project's .t3m file.

Attention Workbench users on Windows: It's possible to make the necessary changes using Workbench, but the procedure is actually a bit easier if you edit the .t3m file manually, so the explanation below assumes you're going that route. Close Workbench before proceeding, and use a different editor, such as Notepad. Don't attempt to edit the .t3m file using Workbench or while it's open in Workbench, since Workbench will overwrite any changes you make as long as Workbench has it open.

Here's the procedure to update your .t3m file to use the Web UI:

The first item, -D TADS_INCLUDE_NET, tells the compiler to include the network-related built-in functions. These interfaces aren't included by default because they're not universally supported on all interpreters, and a game that includes them won't run on an interpreter that doesn't support them. This makes it better to omit them unless you actually make use of them, which of course you must for a Web UI game.

The second item, -lib adv3/adv3web, selects the Web version of the Adv3 library. Adv3web emulates all of the programming interfaces from Adv3 related to basic command-line interactions, such as displaying text or HTML output, reading command lines, reading keystrokes, and so on. This lets you write a Web UI game as though it were a standard console-based game.

The third item, -lib webui -source tadsnet, adds the TADS Web UI library to the build, along with some helper classes for the networking interfaces. The Web UI library is a separate component from Adv3web. Adv3web doesn't actually implement the Web interface, but rather implements an emulation of the traditional Adv3 input and output functions on top of the Web UI library. The Web UI library is a whole separate subsystem that consists of a Javascript library that runs in the user's Web browser, and a TADS library that runs on the server machine hosting the game. The TADS and Javascript portions communicate with each other using the TADS networking system.

The Web UI library is analogous to the traditional input/output functions built into the interpreter. With traditional console-based games, you always had the option to bypass the Adv3 library and work directly with the interpreter built-ins. For Web-based games, you similarly have the option to bypass the Adv3web library and work directly with the Web UI library. If you do so, of course, your game will be inextricably tied to the Web UI - you won't be able to easily port it back to the console UI later. But the trade-off is that you can exploit the full power of Javascript in the browser.

Depending on how much custom UI work you use in your existing game, the library additions above might be all you have to do. The Adv3web library emulates the input and output functions in Adv3, so you won't have to change anything related to displaying text or reading input as long as you used Adv3 functions for I/O rather than calling the interpreter built-ins directly.

If you use any HTML image or audio files, such as JPEG images, there's an extra step. See resource files below.

To test your game in Web UI mode, recompile with the .t3m changes above. If it compiles successfully, try running it. If you're using Windows, HTML TADS will run a Web UI game locally as though it were a standard game - so you don't have to set up a Web server to test Web UI mode.

If you encounter any compiler errors building your game after making the .t3m changes, you must have used a part of Adv3 that isn't supported in the Web version. The most likely missing piece is the banner API - Adv3web doesn't support it. The Javascript front end has analogous capabilities, but the specifics are different enough that there's no Adv3web emulation for the console-mode banners.

If the game compiles successfully, but doesn't work correctly when you run it, your game probably calls built-in functions in the interpreter rather than using the Adv3 equivalents. You'll have to examine your code and eliminate calls to built-ins.

Building the same game both ways

If you stick to the basic command-line user interface, and you're careful to use Adv3 library methods for all of your input/output operations, porting from the console UI to the Web UI is usually just a matter of changing your .t3m file as described above.

An interesting implication is that you can easily create both UI versions of your game from the same set of source files. If you create two copies of your .t3m file - one for the console UI, and another for the Web UI - creating the two versions is just a matter of compiling the game with each .t3m file.

Why would you want to do this? The main reason is to accommodate different users' preferences. Playing on the Web has a number of advantages (greater portability, no need to install anything, the ability to resume a saved game on different machines, multi-user collaboration), but the traditional console UI has some advantages of its own (faster response time, no need to be connected to the Internet while playing). Offering both versions of your game lets users pick the mode that works better for them.

Here are some tips for creating a dual-mode game:

Resource files

If you use HTML resources such as images or audio files (JPEGs, PNGs, MP3s, etc), there's an extra detail to tend to: you have to tell the library that it's okay for client browsers to download those files. The library is cautious about network security, so by default it doesn't let clients download anything without your say-so.

It's fairly easy to specify resource download permissions. First, you should group your resources into one or more folders - that is, subdirectories of your main project folder for the game. Second, for each folder, add an object definition like this to your game:

WebResourceResFile
   vpath = static new RexPattern('/foldername/')
;

That tells the library to treat anything in the "foldername" subdirectory of the game folder as an HTML resource, allowing the client browser to download those files. It's just an ordinary object definition, so you can put it anywhere in your source code that object definitions are allowed. If you divide your resources into multiple folders, just add a definition like the one above for each folder. (You don't have to do this for subfolders, though - the '/foldername/' definition will allow files in subfolders 'foldername'.)

QUIT, disconnect, and program termination

In the traditional console UI, the way the game program terminates is fairly straightforward. When the player types QUIT, the Adv3 command loop exits, which unwinds the call stack until the main() function returns. This terminates the game program, at which point the interpreter program exits to the operating system. Alternatively, on GUI versions (such as QTads or HTML TADS), the player can end the program by closing the main window. This is processed in much the same way as QUIT internally: the interpreter sends an "end of file" indication to the command loop, to let it know that no more input is forthcoming (as there's no way for the player to enter more input without the main window), causing the command loop to exit.

With the Web UI, things aren't quite as simple. The complication is that the player and the game are on separate computers. At first glance, it might seem as though we could take the same approach: if the player types QUIT or closes their browser, we should simply let the TADS program terminate as usual. But what happens if the player's network connection momentarily lapses? We obviously don't want to treat that the same way as an intentional disconnection, but it's not always possible to tell the difference with the network protocols involved. And what happens if the player presses the Refresh button in their browser? It turns out that "Refresh" and "Close Page" are essentially indistinguishable from the perspective of a Web page. Further, what happens if the player types QUIT, but still wants to see what's on the page for a while after? If they try to refresh the page after typing QUIT, the server - the game program - still has to be running to service the request.

To handle these various situations, the Web UI has to use a different approach to managing its session lifetime. For the Web UI, the program's job is larger than merely running the game; it's also acting as a Web server. The Web server's lifetime isn't defined by the duration of the game session, but rather by the existence of connected clients: as long as there's a client connected, the Web server needs to be available to service any new requests from the client.

As we mentioned above, the network protocols we use don't tell us with certainty whether or not a client is connected. More precisely, they don't tell us with certainty that a client is not connected. We can tell for sure that a client is connected, because if we receive a request message, we know that it had to come from a connected client. But the absence of any requests doesn't necessarily mean that there are no clients; it could simply mean that the client doesn't have any work for us at the moment, or that the client computer is tied up doing something else before it can issue its next request, or that a network glitch has temporarily delayed messages from the client.

The Web UI has a two-pronged approach to dealing with all these uncertainties. First, the Javascript portion of the UI uses a publish/subscribe model to maintain a continuous communication channel with the server. The server uses this channel to send periodic "keepalive" messages to the client when no other messaging activity is taking place. This ensures that the client and server exchange messages with a minimum frequency (about every 90 seconds - frequently enough to allow reasonably timely detection of a disconnected client, but rarely enough that the extra messages won't affect network performance). Second, the server monitors client sessions for long periods of inactivity. When a client doesn't responds to our "keepalive" messages for longer than a certain interval (about 60 seconds), we assume that the client has disconnected. When we haven't heard from any clients for a certain interval (about 120 seconds), we assume that the player must be finished with the game. This the point when the program exits and the interpreter terminates.

The timeout intervals mentioned above are nothing magical; they're just parameters in the Web UI server code, chosen based on practical experience. Detecting a disconnection is inherently probabilistic: we can never be certain a client is never coming back, no matter how long it's been since we last heard from them, but the longer we go the more likely it becomes that we have a disconnection rather than something temporary like a network glitch or client-side CPU bottleneck. The practical goal is to choose timeouts that let us shut down the server-side program as soon as possible when it's no longer needed (so that the server machine resources aren't tied up longer than necessary), but no sooner.

Note that when running in local stand-alone mode, some interpreters maintain a direct connection to the browser window that allows them to detect when the player closes the window. This bypasses the timeouts and allows the game program and interpreter to terminate immediately when the player closes the browser window. This is possible in standalone mode because everything's running on one machine, which eliminates the uncertainties of the network configuration and allows the interpreter to know exactly what's going on with the browser. The Windows interpreter provides this feature.

Local single-machine (stand-alone) testing

One of the main reasons to create a Web UI game is that it allows users to play on the Web, without having to download your game or install software. However, Web UI games can also be played without a Web server, a browser, or a network connection. Most TADS interpreters let you play a Web UI game in "local" mode, also known as standalone mode - this means that you run the game on a single computer without a Web server involved.

You'll probably want to use standalone mode while you're developing and testing your game, since it would be inconvenient to have to upload your game to a server every time you recompile.

Debugging with Workbench on Windows

If you're using Workbench on Windows to develop your game, standalone mode is the default way of running. When you use the Go command, Workbench automatically runs the game in standalone mode. Everything looks just like it does with a traditional console-mode game. The only difference is that the game window is actually an embedded Web browser - but this is all handled invisibly, so you don't have to worry about launching a browser separately or typing a URL or anything like that.

As we described earlier, a Web UI game continues running even after the player types QUIT, so that it can continue to provide HTTP services as long as the client is connected (to allow page refreshes, for example). This can be a little strange when you're using the debugger. There are two simple ways to truly terminate the game program: you can close the game window, or you can use the Terminate Game command in the debugger. Closing the game window triggers a special message to the game program that tells it to terminate immediately, bypassing the usual timeout intervals that would otherwise keep the game running for a while longer. When you use the Terminate Game command, this directly ends the game program.

Adv3web usage tips

When using the Adv3web library, there are some additional things you should do to make sure your game works correctly.

Use aHref() for command links

In HTML TADS games, you can use <A HREF=xxx> to create clickable command links. With the Web UI, all HTML is displayed by a standard Web browser, so the <A HREF> tag has its standard meaning, which is to create a hyperlink to a separate Web page.

To create a command link, use the Adv3web function aHref():

"To save the game, type <<aHref('SAVE')>>. "

You should continue to use <A HREF> for actual hyperlinks, where the link navigates to another Web page rather than entering a command, as well as for special links such as mailto: links.

Don't use <TAB>

The <TAB> tag is an HTML TADS extension that isn't in standard HTML. Standard Web browsers don't support it. Unfortunately, standard HTML doesn't have a simple equivalent of <TAB>, but you can usually achieve similar effects using <SPAN> or <DIV> tags with CSS styling to control spacing.

Use inputManager methods for input

As we've already mentioned a couple of times, you can't use the interpreter's built-in functions for input and output. The built-ins all operate directly on the local console, which obviously isn't available to a remote user playing on the Web.

Instead of the interpreter built-ins, always use the Adv3web equivalents:

Note one small difference with timed command-line input: if a call to inputManager.getInputLine() is interrupted by a timer event (such as a real-time daemon or fuse), the Web version doesn't return the text on the interrupted command line. This is because the timeout occurs on the server side, so obtaining the partial text would require an extra network request to ask the browser for the information. The library doesn't make this extra request, since it would take extra time, and the information isn't usually needed anyway.

Use cls() instead of clearScreen()

You shouldn't use the built-in function clearScreen(), just as you shouldn't use any other built-in I/O functions. Use cls() instead - this will work correctly in both Adv3 and Adv3web.

Don't use the Banner API

The Banner API isn't supported in Adv3web. This includes both the low-level banner functions built into the interpreter and the Adv3 BannerWindow class.

The Web UI provides similar capabilities, but it uses a new programming interface. The new system is much more flexible than the banner API because it uses Javascript and CSS in the client. This combination isn't limited to the "tiled" model of the banner API - you can create overlapping windows, create transparent windows, move windows dynamically, set sizes using font metrics, etc. The new system is so different that it makes more sense to work directly with the new interfaces, so that you can take better advantage of their new capabilities.

Note that Adv3web does provide the higher-level components that were built on the banner API in Adv3: the status line, the menu system, and the hint system. The Adv3web versions of these components are built directly on the new Javascript front end instead of the banner API.

Sound playback

The <SOUND> tag is an HTML TADS extension that's not in standard HTML, so you can't use it for sound playback in Web UI games.

There's currently no support for sound playback in the Web UI library. We plan to add this in the future. For the moment, if you need sound playback, you'll have to resort to direct Javascript programming.

<ABOUTBOX>

The <ABOUTBOX>> tag is an HTML TADS extension, not part of standard HTML. You shouldn't use this tag. There's currently no equivalent in the Web UI. However, note that the Adv3 library only calls gameMain.setAboutBox() when running in console mode, so it's fine to write your <ABOUTBOX> code as usual in that method.

Direct Javascript programming

So far we've focused on how the Web UI is practically invisible from a programming perspective - how everything works exactly like it does in the traditional UI, as long as you stick to the Adv3 input/output functions. We've focused on this transparency because we expect many authors will be interested in the Web UI primarily for its ability to eliminate installation requirements for players. As we've seen, this "Web deployment" capability can be included in new games or added to existing games with very little extra work.

However, there's another benefit to the Web UI that we've barely mentioned so far: it has much more powerful UI capabilities than text-only TADS or even HTML TADS. Adventurous authors who wish to go beyond the compatibility features in the Adv3web library will discover a whole new frontier in the Web UI.

The key to the Web UI's expanded power is that the user interface runs in a true Web browser, not in a TADS interpreter. Modern Web browsers are extremely sophisticated UI application platforms, far beyond what the TADS interpreter can offer.

When you create a TADS Web UI game, there are two libraries involved. The first is Adv3web: this is the component that emulates the traditional Adv3 input/output functions, to make it easy to write games that require only the basic command-line style of interaction. When you use Adv3web, you'll barely notice that you're using the Web UI at all from a programming perspective, since everything works just like in the regular console UI. The second library is the Web UI library: this is the library that actually implements the Web UI. It has its own separate programming model that's not based on anything in Adv3, but rather is designed to provide direct access to the browser's capabilities.

The Web UI library is different from any other TADS library, in that it's not just TADS code. It also contains HTML, CSS, and Javascript code. These files are in the "resource" section of the library. They're compiled into your game, and your game sends them to the browser.

The Web UI library's TADS code, Javascript, HTML, and CSS are designed to work together. The HTML defines the basic templates for the pages, and initiates the Javascript. The CSS defines the layout style information for the HTML. The Javascript code uses XML Requests (also known as "AJAX") to communicate with the TADS code through an HTTP network connection. The TADS code uses the TADS networking system to serve the HTTP XML requests.

The really interesting thing about this setup is that all of the HTML, Javascript, and CSS are part of the game program. They're bundled into the .t3 file, and the game transmits them to the browser via HTTP. This means that everything about the Web UI is open for you to inspect, change, and extend.

The browser-side code making up the Web UI library is contained in the webuires subfolder of the Web UI library folder. The code consists of these main components:

The TADS code for the Web UI is in the file webui.t. This file defines TADS classes corresponding to the various Javascript widget objects. It also provides a framework for handling Ajax requests from the client, and a publish/subscribe framework that allows the server to send updates and requests to the client.

Some of the key objects, classes, and functions in webui.t:

To customize or extend the Web UI, you'll obviously have to know not just TADS but also the standard Web technologies in the resource components - Javascript, CSS, HTML, Ajax. It's beyond the scope of this chapter to provide tutorials for any of these, but it's easy to find that sort of information on the Web.

One thing we will mention on the Javascript side: the Web UI resource folder, called webuires (it's a subfolder of the main TADS system library directory) contains a useful Javascript file called util.js. This is a collection of utility functions that make it easier to write Web UI code in Javascript, and you can easily include it in your own custom HTML pages using the <SCRIPT> tag. The utility functions fall into three main categories: