[vworld-tech] Web Browser as Interactive Client

Donovan Preston dsposx at mac.com
Sun Jan 25 22:44:02 PST 2004

On Jan 25, 2004, at 2:18 PM, ceo wrote:
> Brian Hook wrote:
>>> you think about it - do you really need it?
>> It's also a client available right now, so I can do server 
>> development and defer client development later.
> I agree this is very valuable indeed. However, IMHO web-browsers are 
> now a more sensible choice for this, where possible.
> For someone trying to get experience of "traditional", old-skool MUD 
> design and dev, www is not a good idea because it makes the GUI much, 
> much nicer than a traditional MUD :P.
> There are many people doing serious, boundary-pushing, work in MUD's 
> these days, and AFAICS it's usually nothing to do with "loving the 
> feel of that old line-based (can't bind to keypresses!) UI". IMHO a 
> crappy telnet client is NOT one of the fundamental advantages of a MUD 
> (although the *ubiquity* of said client certainly is...).
> The only serious reason I've seen not to use www as your LCD UI is the 
> lack of push in the HTTP protocol. You can easily work around this, 
> and although many people create special non-www clients (e.g. embedded 
> java clients, because web-browsers are too rigidly pull-based in their 
> design) to speak their "embraced and extended" version of RFC 2616, 
> this isn't at all necessary.

I agree completely. Back when I started hacking MOO, the WWW didn't 
exist yet, but I guess around 94 or 95 people started experimenting 
with writing HTTP servers in-MOO and I wrote my first webapp in 
moocode. The possibilities of combining the moo server with hypertext 
were pretty compelling, but I think people quickly became disheartened 
by the lack of any way to push updates to the browser and wrote off the 
idea as infeasible.

Around this time, wanting to continue development of a multimedia moo 
experience, I began writing a standalone client which would be able to 
display pictures, play sound, respond to clicks and drags, et cetera, 
but it got bogged down in the difficulties of developing cross-platform 
applications. (I was mostly using the Mac and wanted to support the PC, 
but Windows 95 hadn't even been released when I started development!) 
So, I put the project aside. Fast forward 10 years...

> A litle lateral thinking can get you to a very effective MUD whose LCD 
> UI is a web-browser which supports meta refreshes (which means all of 
> them, these days). There's *very* little difference between a MUD with 
> a global 1-second tick, and a framed webpage with a chat-window 
> running on a 1-second auto-refresh...

When it comes to LCD, this is even more common than a telnet client. 
*Everyone* has a web browser that can do meta refresh. Not everyone has 
a telnet client, and even fewer still know how to use it. Even if you 
really, really want to support telnet for that x% of your hardcore 
userbase, this fact should at least invert the priorities, putting the 
web UI first.

> But you can get waaaay more interesting (and powerful, and 
> easy-to-use) than that, without making your job as 
> server/quest/content coder/author significantly harder. In fact, I 
> have a hobby-project at the moment... I promise I'll post when (if) I 
> have something interesting to see :).

I'm interested in knowing what sneaky tricks you have up your sleeve, 
because I have a bundle of my own :-) Let me enumerate.

First, let me outline the requirements: We would like to have the 
ability to push server-side events to the browser, without the browser 
polling for these events. We would like the ability to update the 
client-side page without refreshing the whole thing, as this can be 
slow. We would like the ability to send client-side user input to the 
server without refreshing the whole page.

And some anti-requirements: I'd rather not use Java applets. I'd rather 
not support Netscape 4. (All for moral reasons...)

My first successful in-browser client was built using frames. Each 
frame has it's own src attribute, and the browser loads each frame 
separately. When you first load the page, the initial splash screen 
goes on the main visible body of the page, and two invisible <iframe> 
elements are placed at the bottom of this page. One is labeled "input" 
and the other is labeled "output".

The browser then attempts to load these two iframe documents using 
individual tcp sockets (glossing over HTTP/1.1). Since the user hasn't 
provided any input yet, the server responds to the input frame with a 
dummy page. However, the server responds to the output frame by writing 
a little bit of data and then stalling. And here is the bit of magic: 
Assuming the browser supports HTTP/1.1 chunking (which every browser 
does nowadays), the server can hold this socket open indefinitely, 
writing noops regularly to keep it alive. Then, in response to a 
server-side event, the server can write a chunk of data with a <script> 
tag containing the JavaScript to execute on the client.

The JavaScript you write is then similar to any other sort of 
client-side DHTML one might write (Which is to say, laden with bugs and 
cross-browser incompatibilities ;-) You could use a script to swap an 
image (your health meter) or change a number in a text box (your 
health). However, there is one technique which works reliably 
cross-browser on modern browsers which I prefer to use: innerHTML.

The innerHTML property allows you to... wait for it... change the HTML 
inside a particular DOM node. If your server had enough information 
about the current HTML contents in the browser, and had been careful to 
place unique id= attributes on all of the nodes which could possibly 
need changing, then this property can allow you to make dramatic, 
sweeping changes to your pages without really writing much javascript 
at all.

Sending user input to the server is perfectly straightforward and easy. 
You place javascript event handlers on all of your input devices 
(<input> text boxes, buttons, images, etc) and in these handlers, 
change the src attribute of the "input" iframe, encoding the arguments 
you wish to send to the server in the URL. You will want to write a 
client-side queue of events so you don't start writing a new event to 
the server before the first event has completed being sent.

This technique will work reliably on ALL modern browsers. If you switch 
to using regular frames instead of iframes and restrict yourself to not 
using the innerHTML trick, this technique can even be used on Netscape 
Navigator 4 (shudder). There are even a few more advanced techniques 
which are even nicer and more reliable: One involves embedding a small 
invisible Flash movie in your page and using the Flash XMLSocket, which 
is persistent and can both send and receive (can't send null bytes, 
though). The other involves using the browser-specific XmlHttpRequest 
APIs (In Mozilla; Internet Explorer has another, 
similar-but-not-the-same API). The XmlHttpRequest technique is 
functionally identical to the iframe technique, except the browser 
"loading" indicator will not continue to throb, as happens with the 
frame technique.

But you don't want to use any of these techniques ;-) What you really 
want to do is use my web application framework Nevow, which abstracts 
all of these techniques away from you, does the browser sniffing for 
you, and lets you write python code like this:


Where self.onExamine is a server-side python function, and 
"getValue('examineWhat')" is a client-side JavaScript function which 
will be called and whose result will be passed to self.onExamine.

Nevow is available now in CVS for the brave. All that remains to be 
done to package it standalone and make it easy to install is to remove 
some convenient dependencies; it's on my todo list and I should get to 
it around the end of the month. The liveevil module, which is a rewrite 
of my earlier LivePage efforts, is proving to be quite usable and 
powerful. I am currently writing a browser-based clone of the old 
MacMOOSE GUI client which allowed you to introspect MOO objects, edit 
properties, and program verbs using nice GUI tools. I will write more 
about Nevow and post some simple examples of how to use it to connect 
to your MUD (my moose client is less than 200 lines) when I have an 
easy-to-install distribution.


More information about the vworld-tech mailing list