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:
- Web-based play. You can set things up so that users can play your game directly in a browser, without installing your game or any TADS software on their machines. Users simply point their browser to a URL, and the game runs in the browser window. There's nothing for players to download or install - not even a plug-in, since the UI is built entirely on standard Web technologies that are native to all modern browsers (HTML, CSS, Javascript, and AJAX). Your game and the TADS interpreter run on a separate Web server machine; the user only needs to know the URL to the server, which you can easily supply via a hyperlink on your own Web page.
- Full support for Javascript, CSS, and HTML DOM. The traditional HTML TADS user interface uses an "extended subset" of the older HTML 3.2 standard, and has no support for CSS, Javascript, or HTML DOM access. With the Web UI, you have access to all of those technologies, plus full standard HTML, because the UI runs in an actual browser. HTML TADS is certainly more optimized for the traditional text game UI than a browser is, but the trade-off is that it's narrowly focused on that one type of UI. Web browsers are much more flexible and powerful as UI platforms.
- Multiuser gaming. A key TADS feature that makes the Web UI possible is a network server capability. The network capability goes beyond just talking to the browser, though: it's really a full-featured networking layer that lets a game communicate with multiple clients, opening up numerous possibilities for collaborative and multi-user games. Although the Adv3 library is only designed for a single player character, its new Web UI support does allow multiple people to connect to the same session and play the game collaboratively.
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:
- the banner API
- sound playback
- non-standard TADS HTML tags
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.
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:
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:
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'.)
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.
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.
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.
When using the Adv3web library, there are some additional things
you should do to make sure your game works correctly.
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():
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.
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.
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.
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.
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.
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.
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.
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:
Building the same game both ways
#ifdef TADS_INCLUDE_NET
special code for the Web UI goes here
#else
special code for the console UI goes here
#endif
Resource files
WebResourceResFile
vpath = static new RexPattern('/foldername/')
;
QUIT, disconnect, and program termination
Local single-machine (stand-alone) testing
Debugging with Workbench on Windows
Adv3web usage tips
Use aHref() for command links
"To save the game, type <<aHref('SAVE')>>. "
Don't use <TAB>
Use inputManager methods for input
Use cls() instead of clearScreen()
Don't use the Banner API
Sound playback
<ABOUTBOX>
Direct Javascript programming