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.
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.
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!