chris@arachsys.com GitHub Chris Webb

AutoUI

The DOMancer: summon a user interface from an empty page

This demo runs an OpenRouter model in a tiny JavaScript loop on a blank HTML page, giving it only the ability to eval() expressions. The model figures out the setup, builds a DOM interface from scratch to talk to you, and can create other impressive graphical HTML toys on the fly.

Start by checking out the simple source code, then enter a valid API key, choose a model, open the browser console to keep an eye on the model’s activity, and hit Go. Leave the key blank to provision one using OpenRouter’s OAuth PKCE.

Notes

Recent but cheap models like openai/gpt-6-luna, openai/gpt-6-luna-pro, and anthropic/claude-haiku-5.5 are a good starting point; it typically costs around $0.0005 to one-shot an inviting chat interface with Luna 6, and around $0.0007 with Haiku 5.5.

To open the console on a desktop browser, use the following keyboard shortcuts:

Browser Linux macOS Windows
Chromium ⌃⇧J ⌥⌘J ⌃⇧J
Firefox ⌃⇧K ⌥⌘K ⌃⇧K
Safari — ⌥⌘C —

With Safari, you might need to enable Show features for web developers first. Other browsers are less patronising. The demo works fine on mobile devices too, but you can’t easily watch the console to monitor progress there.

The blank page sits apparently idle for a short time while the model reasons about the setup, and larger models can think for thirty seconds or more before returning with something imaginative. If the API call drops or fails, or if any other error occurs, a dialog box reports this. Reloading the page restarts generation from scratch, so if you get a boring first turn, it’s worth retrying.

Most modern models quickly understand the scenario, and correctly block awaiting user input where appropriate. There is a small risk of a confused model calling the API in a busy loop, so it’s best to limit the amount of credit available to the key you use, and keep an eye on activity in the console at first. After a model has successfully waited, it’s unlikely to end up spinning on a later turn.

Once you can communicate, you can say things like “Let’s play Doom!” or “How about a 3D simulation of a galaxy?” or “Can you build a musical instrument?” or “Please surprise me!” with invariably impressive results.

At the time of writing, anthropic/claude-opus-5.5 is thwarted by Anthropic’s censorship zealots, right after reading the page’s source code. Presumably this is a false positive, but who knows how far these hysterical people have stretched their fear of dangerous thoughts?

You don’t need to use the client-side form above to run the demo. It’s a simple static page and just expects key and model as URI-encoded parameters in the hash part of the URL. Usually neither the key nor the model slug requires escaping. You can also specify api to override the responses endpoint, reasoning to set the reasoning effort level, and search to enable the native web search tool. The page runs fine downloaded to a local file.

An early prototype exposed eval() as a custom tool, but this encouraged smaller models to address the user with assistant replies even when directly told or shown that the harness ignores them. Repurposing the main communication channel for JavaScript worked much better.

Implementing PKCE for the form above turned out to be surprisingly simple. Inspect the source of this page or a stand-alone version for the details. The code is in two halves: the request happens in the Go button click handler if key.value is empty, and the callback is dealt with at top level when the module is evaluated.

Contact

This toy was hand-made by Chris Webb <chris@arachsys.com> and is distributed as Free Software under the terms of the MIT licence. Have fun!