Dev log ยท 2026-10-13

WebRebol: REBOL 2 in the browser, for very small interactive pages ๐Ÿ“œ

We wanted a script of approximately 1000 characters that makes an interactive page. An LLM must be able to write the script. The script must not have the full power of the JavaScript of the page.

WebRebol is our answer. It is an interpreter for REBOL 2 Core and REBOL 2 View in plain JavaScript, with no dependencies. We test it against the REBOL 2.7.8 program itself.

The objective

We had three conditions for the language of the script.

JavaScript is the best for the second condition, and the worst for the other two. A new language of our own is good for the first and the third condition, but no LLM knows it.

Why REBOL 2

Carl Sassenrath made REBOL in 1997. Before that, he designed the kernel of the Amiga operating system. REBOL has dialects. A dialect is a small language in a block of data, and it does one job. The layout dialect describes a window. The parse dialect describes a grammar. The draw dialect describes shapes.

This is a full Pong game for WebRebol. It has 1064 characters.

score: 0 speed: 4x3
step: does [
    ball/offset: ball/offset + speed
    if any [ball/offset/y < 0 ball/offset/y > 290] [speed: speed * 1x-1]
    if ball/offset/x > 390 [speed: speed * -1x1]
    if all [
        speed/x < 0
        ball/offset/x < 18
        ball/offset/x > 4
        ball/offset/y + 10 > paddle/offset/y
        ball/offset/y < (paddle/offset/y + 60)
    ] [
        speed: speed * -1x1
        score: score + 1
        label/text: form score
    ]
    if ball/offset/x < -10 [score: 0 label/text: "0" ball/offset: 200x150 speed: 4x3]
    show court
]
court: layout [
    origin 0x0 space 0x0
    box 400x300 20.20.40 rate 60 on-time [step] on-key [
        if all [key = "ArrowUp" paddle/offset/y > 0] [paddle/offset: paddle/offset - 0x20]
        if all [key = "ArrowDown" paddle/offset/y < 240] [paddle/offset: paddle/offset + 0x20]
    ]
    at 10x120 paddle: box 8x60 white
    at 200x150 ball: box 10x10 yellow css [border-radius 5]
    at 150x8 label: text 100x30 "0" css [color 255.255.255 font-size 22 text-align "center"]
]
view court

The script has no element queries, no event listener functions, and no style sheet. The layout block puts the faces on the page, and the blocks after a face are its actions.

REBOL 2 is also a stable target. Its last release, 2.7.8, came in 2011, and the language does not change. Many REBOL 2 scripts and documents are public, thus LLMs write it sufficiently well. The newer relatives, Red and Ren-C, continue to change, and LLMs mix their rules.

An LLM makes errors in REBOL more frequently than in JavaScript. A script of 30 lines is easy to run and to correct, and the interpreter gives an error message that tells the cause.

Not full-page JavaScript

WebRebol does not change a script into JavaScript, and it does not use eval. It is a machine with an explicit stack that reads REBOL values. A script can use only the words that the session gives to it.

One gap is open at this time. The web word element accepts all tags and all attributes. Thus a script can make an element that runs JavaScript or that loads a remote address. A filter for tags and attributes is the next work. Until then, run only the scripts that you trust.

The explicit stack has a second purpose. A browser page cannot block, but REBOL functions such as view, wait and input do block. In WebRebol, such a function stops the machine with a request. An edge module does the work, and the machine continues with the answer.

How we know that it is REBOL

We do not trust our memory of REBOL, and we do not trust the memory of an LLM. The REBOL 2.7.8 program runs on the development computer, and it is the reference.

ComparisonResult
Cases of the project, recorded from REBOL 2.7.8All 2435 cases agree.
The public REBOL core test suite4347 of 4586 tests give the same outcome (94.8%).
Load of downloaded REBOL scripts529 of 538 scripts agree.
Core functions382 of 443 have a first version.

Most of the 61 functions that remain are not possible in a browser: email, sockets, and the start of other programs. The comparison also found defects in REBOL itself. For example, REBOL 2.7.8 for 64-bit Linux gives MD5 results that are not correct. WebRebol does not copy such a defect. A separate list records each one.

WebRebol has no code of REBOL Technologies. REBOL Technologies did not publish the source of its interpreter. We wrote each function again from its behavior, and the functions that REBOL writes in REBOL are new text.

View: from desktop windows to the page

REBOL View draws its own windows on a desktop. WebRebol keeps the REBOL part and replaces the drawing part.

theme/font-family: "Georgia"
append theme/css [button [border-radius 6 background-color 20.120.60]]
view layout [button "OK" button "Special" css [background-color 150.40.40]]

Files: a disk that the host page owns

REBOL scripts read and write files. A browser page has no file system, and a script must not read the files of the computer.

WebRebol has a disk in memory. It is a table of full paths, and each entry is a folder or a file with its bytes. read, write, load, save, do, the directory functions and file ports operate on this table.

WebRebol has no storage code. The host page gives the disk to a session, and it gets the changed disk back at the end. The page then saves the disk as it prefers, for example in an encrypted store. In Node.js, the disk is a folder.

import { interpretWithEdge } from "./src/edge/drive.mjs";

const machine = await interpretWithEdge('write %note.txt "hello"', 5000, disk);
const nextDisk = machine.store.disk;

Web Crypto in REBOL words

REBOL 2 has checksum and a small set of old ciphers. A browser has Web Crypto, and Web Crypto is modern. WebRebol adds words for all its algorithms.

key: crypto-derive "a passphrase" crypto-random 16 600000
sealed: crypto-encrypt "a secret text" key
to-string crypto-decrypt sealed key        ; "a secret text"

mine: crypto-key-pair/method 'x25519
yours: crypto-key-pair/method 'x25519
secret: crypto-agree second mine first yours

The words include digests, AES-GCM, key pairs (ECDSA, Ed25519, RSA), PBKDF2, HKDF, ECDH and X25519. Web Crypto is asynchronous, but a script is not. The machine waits while the browser does the work.

compress and decompress use the compression streams of the browser in the same manner. Thus WebRebol has no compression library.

Music: ABC notation and Web Audio

We also wanted sound. LLMs know ABC notation well, because large public collections of tunes use it. Thus the music words read ABC.

score: abc-to-score {X:1^/L:1/4^/Q:1/4=120^/K:G^/G A B c | [GBd]4 |}
play-audio/with score [sine 1 0.6 sine 2 0.25 fade 0.3 gap 0.1]

The limits

The alternatives

ToolThe reason that we did not use it
JavaScriptIt is the best known to LLMs, but a script is long, and it gets the full power of the page unless you isolate it.
Ren-CIt runs a Rebol dialect in a browser with WebAssembly. It is not REBOL 2, it has no layout dialect, and it continues to change.
Lua or JanetThe two are good small languages, but they have no dialect for a page. Each script must build its page with function calls.
A language of our ownNo LLM knows it, and it has no reference program to test against.

If your objective is only an interactive page, use JavaScript. WebRebol is the correct tool when the size of the script and the limits on its power are important.

Try it

git clone https://github.com/rheophile10/webrebol
cd webrebol
node bin/serve.mjs

Then open http://localhost:8017/. The start page has games, a paint program, the music page and an editor. Only Node.js is necessary. The project has no packages to install.

References

More from the dev log