# \-- WebRacket --

**URL:** <https://racket.discourse.group/t/webracket/4123>\
**Category:** General\
**Created:** [February 22, 2026, 10:46pm UTC](https://racket.discourse.group/t/webracket/4123 "2026-02-22T22:46:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 22, 2026, 10:46pm UTC](https://racket.discourse.group/t/webracket/4123/1 "2026-02-22T22:46:07Z")

</div>

Hi All,

For some time been working on a Racket to WebAssembly compiler.

Today the website went live:

[https://soegaard.github.io/webracket/](https://soegaard.github.io/webracket/)

/Jens Axel

---

<div class="post-metadata">

**Author:** ![gus-massa](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/gus-massa/32/507_2.png) [@gus-massa](https://racket.discourse.group/u/gus-massa)\
**Post date:** [February 23, 2026, 2:40pm UTC](https://racket.discourse.group/t/webracket/4123/2 "2026-02-23T14:40:28Z")

</div>

Feature request for the space invaders demo:

Back in my days, there could be only one bullet in the screen (due to a sprite number constrain?). So missing a shoot was painful because I had to wait until the bullet reached the top of the screen. In this version I can just press space to shoot, and it removes part of the anxiety shooting the few last invaders.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 23, 2026, 2:53pm UTC](https://racket.discourse.group/t/webracket/4123/3 "2026-02-23T14:53:09Z")

</div>

I'll add a hard mode!

---

<div class="post-metadata">

**Author:** ![jjsimpso](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jjsimpso/32/602_2.png) [@jjsimpso](https://racket.discourse.group/u/jjsimpso)\
**Post date:** [February 23, 2026, 4:05pm UTC](https://racket.discourse.group/t/webracket/4123/4 "2026-02-23T16:05:01Z")

</div>

Not necessary for a code demo, but I agree this is an essential aspect of the space invaders "experience!"

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 23, 2026, 8:22pm UTC](https://racket.discourse.group/t/webracket/4123/5 "2026-02-23T20:22:52Z")

</div>

@gus-massa @jjsimpso

[https://soegaard.github.io/webracket/new/space-invaders.html](https://soegaard.github.io/webracket/new/space-invaders.html)

I have added a new hard mode. It's tricky to calibrate the difficulty.  
Let me know if it is too hard.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 23, 2026, 8:23pm UTC](https://racket.discourse.group/t/webracket/4123/6 "2026-02-23T20:23:43Z")

</div>

Hi All,

From the feedback yesterday the main points were:

1. the compiler overview was not useful as is
2. the design was too much AI
3. some text was too much AI

Ad 1. I rewrote the compiler overview. It is no longer short. [https://soegaard.github.io/webracket/documentation-compiler-overview.html](https://soegaard.github.io/webracket/documentation-compiler-overview.html)

Ad 2. I have attempted to make an alternative design. Use the new/old button in the uper right corner to switch between them. Far from all pages have been polished for the new design. However, check out the same compiler overview in the new design: [https://soegaard.github.io/webracket/new/documentation-compiler-overview.html](https://soegaard.github.io/webracket/new/documentation-compiler-overview.html) Also, check also the front page.

Ad 3. I have rewritten the worst cases of AI inspired wording. However, I need help to improve the text.

What's the verdict - is the new design worth pursuing or should I stick to the dark one?

---

<div class="post-metadata">

**Author:** ![gus-massa](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/gus-massa/32/507_2.png) [@gus-massa](https://racket.discourse.group/u/gus-massa)\
**Post date:** [February 24, 2026, 10:03pm UTC](https://racket.discourse.group/t/webracket/4123/7 "2026-02-24T22:03:20Z")

</div>

I can't find the licence of the project. Are you planing to add one later?

Did you forget to commit space-invaders-rkt? I disagree with the bullet behavior in hard mode, and I was thinking about sending a PR instead of explaining the difference. (I can write the difference if you prefer.)

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [February 24, 2026, 10:13pm UTC](https://racket.discourse.group/t/webracket/4123/8 "2026-02-24T22:13:26Z")

</div>

Wonderful. I installed it, ran the examples locally .. but now I feel dumb because I can’t get my own program to run. And the Quick Start doesn’t have a section that says “here is how you run your own Racket programs in the browser.” Could that be added next for people like me? Thanks.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 24, 2026, 11:07pm UTC](https://racket.discourse.group/t/webracket/4123/9 "2026-02-24T23:07:01Z")

</div>

@gus-massa

Things are a little messy now, I am experimenting with a new website design.

Space Invaders on the dark website is here:

> <https://github.com/soegaard/webracket/blob/main/web-site/src/examples/space-invaders-page.rkt>

To build it, to go `web-site/src` and use `./build.sh` this will the dark web site.  
Then go to `web-site/local/` this folder holds the website.  
Run `raco static-web` and open the web-site in the browser.

But - since this build the entire web-site including all examples building is a little slow.

The alternative is to change `examples/space-invaders /space-invaders.rkt` which is a standalone example.

But I think the latests change haven't been made here - so you might need to copy from the web-site version. That folder has build instructions in the readme.

PS: I would love to receive my first PR.

/Jens Axel

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 24, 2026, 11:21pm UTC](https://racket.discourse.group/t/webracket/4123/10 "2026-02-24T23:21:31Z")

</div>

> And the Quick Start doesn’t have a section that says “here is how you run your own Racket programs in the browser.” Could that be added next for people like me?

Working on it!

I made 3 hello world examples today, but haven't had time to put them in the Quick Start yet.

> **[webracket/examples at main · soegaard/webracket](https://github.com/soegaard/webracket/tree/main/examples)**
>
> The WebRacket language is a subset of Racket that compiles to WebAssembly - soegaard/webracket

All examples should have build instructions in the readme.  
Most also in the source itself.

The first one, `hello-world-1`, shows that

```scheme
racket webracket.rkt -r 

```

will build the program and run it in terminal (via Node).  
This is useful for automatic testing of non-web related programs.

The second one `hello-world-2` shows how to use `--browser` to build for the browser.  
It generates both an wasm bytecode file and an html file that will load the webassembly and run it. This version uses the dom API to build nodes to display.

Due to security in modern browser, one can't just open the hml file in a browser.  
You need to start a local web-server that serves the file.  
So, one can use `raco static-web` in, say, the root of the repo.

The third one, `hello-world-3`, uses sxml to generate the nodes.

Finally, I should mention that one can use `#lang webracket` in DrRacket to test non-web programs. This language doesn't invoke the WebRacket compiler, but rather provides the primitives and forms that WebRacket currently supports. The idea is two-fold. First, users can develop WebRacket programs with a fast compiler. Second, I can use it to test whether the output of my compiler is correct.

/Jens Axel

UPDATE - Added paragraph on why `raco static-web` is needed.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 24, 2026, 11:22pm UTC](https://racket.discourse.group/t/webracket/4123/11 "2026-02-24T23:22:39Z")

</div>

I forgot to include this:

```scheme
soegaard@mbp3 webracket % racket webracket.rkt --help  
usage: webracket [<option> ...] <filename>

<option> is one of

  -r, --run
     Run the program after compilation.
  -v, --verbose
     Compile with verbose messages
  --wat-file <filename>
     Filename for the wat file
  --wasm-file <filename>
     Filename for the wasm file
  --host-file <filename>
     Filename for the host file
  --label-map-forms
     Include (form ...) entries in .wasm.map.sexp
  --no-label-map-forms
     Omit (form ...) entries in .wasm.map.sexp
  --timings
     Print timing breakdown for compilation steps
  --stdlib
     Include the standard library
/ -b, --browser
| Generate code for browser.
| -n, --node
\ Generate code for Node.js
* -l <lf>, --link-flags <lf>
     Add a flag <lf> for the linker
* --ffi <ffi-file>
     Add .ffi file
  --help, -h
     Show this help
  --
     Do not treat any remaining argument as a switch (at this level)

 * Asterisks indicate options allowed multiple times.
 /|\ Brackets indicate mutually exclusive options.

 Multiple single-letter switches can be combined after
 one `-`. For example, `-h-` is the same as `-h --`.

```

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [February 24, 2026, 11:52pm UTC](https://racket.discourse.group/t/webracket/4123/12 "2026-02-24T23:52:03Z")

</div>

```scheme

[matthias @ CedarPark webracket (main)]$ racket webracket.rkt -r ../test.rkt

compiler.rkt:52:9: collection not found

for module path: nanopass/base

collection: "nanopass"

in collection directories:

/Users/matthias/Hub/SwDev/Lib/

/Users/matthias/0Unison/collects/

/Users/matthias/Library/Racket/development/collects

/Users/matthias/plt/racket/collects/

... [254 additional linked and package directories]

location...:

compiler.rkt:52:9

```

So I installed nanopass. Please do include with installation instructions.

```scheme

[matthias @ CedarPark webracket (main)]$ racket webracket.rkt -r ../test.rkt

standard-module-name-resolver: collection not found

for module path: webracket

collection: "webracket"

in collection directories:

/Users/matthias/Hub/SwDev/Lib/

/Users/matthias/0Unison/collects/

/Users/matthias/Library/Racket/development/collects

/Users/matthias/plt/racket/collects/

... [255 additional linked and package directories]

context...:

/Users/matthias/Wasm/webracket/expander.rkt:16:0: topexpand

/Users/matthias/Wasm/webracket/compiler.rkt:5984:6

/Users/matthias/Wasm/webracket/compiler.rkt:5968:0: comp

/Users/matthias/Wasm/webracket/driver.rkt:49:0: drive-compilation

body of "/Users/matthias/Wasm/webracket/webracket.rkt"

```

Ah, I need to install it as a package. Done.

```scheme

cat ../test.rkt

;; #lang racket

(define (hello w) (display 'world))

(hello 'Jens)

```

Could the compiler error messages be less Node-y?

```scheme

[matthias @ CedarPark webracket (main)]$ racket webracket.rkt -r ../test.rkt

(WARNING unbound? display)

/bin/sh: wasm-tools: command not found

* Compilation Error *

node:internal/fs/promises:642

return new FileHandle(await PromisePrototypeThen(

^

Error: ENOENT: no such file or directory, open '../test.wasm'

at async open (node:internal/fs/promises:642:25)

at async Object.readFile (node:internal/fs/promises:1279:14)

at async file:///Users/matthias/Wasm/test.js:4:20 {

errno: -2,

code: 'ENOENT',

syscall: 'open',

path: '../test.wasm'

}

```

OK, `display` is no good. How about without:

```scheme

[matthias @ CedarPark webracket (main)]$ racket webracket.rkt -r ../test.rkt

/bin/sh: wasm-tools: command not found

* Compilation Error *

node:internal/fs/promises:642

return new FileHandle(await PromisePrototypeThen(

^

Error: ENOENT: no such file or directory, open '../test.wasm'

at async open (node:internal/fs/promises:642:25)

at async Object.readFile (node:internal/fs/promises:1279:14)

at async file:///Users/matthias/Wasm/test.js:4:20 {

errno: -2,

code: 'ENOENT',

syscall: 'open',

path: '../test.wasm'

}

Node.js v24.11.0

```

At this point I am not sure how to proceed. But hey, this is going somewhere and I’d love to see progress.

Do you want actual PRs for these?

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 25, 2026, 12:20am UTC](https://racket.discourse.group/t/webracket/4123/13 "2026-02-25T00:20:25Z")

</div>

The overall lesson is that I need to make a `webracket` package in order to make this easier to install. Maybe make `raco webracket` invoke `webracket.rkt` to make it easier to run.

Anyways, for now I'll

- add instructions on installing `nanopass`
- add instructions on installing `webracket ` as a package  
(I need to spin up a VM, so I can test this from scratch)

Then comes the:

> Could the compiler error messages be less Node-y?

```scheme
> 
/bin/sh: wasm-tools: command not found

* Compilation Error *

node:internal/fs/promises:642

```

What happened here is that `wasm-tools` is missing from your path.  
Thus the wat (text format of WebAssembly) was never compiled to wasm (bytecode).  
The compiler driver should have stopped here - but it continued and made `node` run the non-existing `test.wasm` file. And what you see the error from Node.

I'll improve the compiler driver to check that `wasm-tools` is in the path.

Lastly, in order to use `display` you need to add `--stdlib` as an option.  
This is not obvious. The standard library contains the part that are implemented in WebRacket. This includes reading and writing.

Now that the compiler is somewhat stable, I need to flip it.  
The standard library ought to be be included as default.  
Then a switch `--no-stdlib` could omit it.

Finally, I need to check why you didn't get a normal "identifier unbound" error,  
for `display` when the switch `--stdlib` is not used. That was the expected error message.

You probably already installed `wasm-tools`, but if not:

[https://soegaard.github.io/webracket/installation.html](https://soegaard.github.io/webracket/installation.html)

/Jens Axel

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 25, 2026, 12:33am UTC](https://racket.discourse.group/t/webracket/4123/14 "2026-02-25T00:33:18Z")

</div>

> [@gus-massa](#):
>
> can't find the licence of the project. Are you planing to add one later?

Thanks for the reminder!

I have added a license (MIT).

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [February 25, 2026, 1:31am UTC](https://racket.discourse.group/t/webracket/4123/15 "2026-02-25T01:31:21Z")

</div>

1. I had placed wasm-tools on my path or so I thought .. wrong.

2. When I did place it on my path, I got the usual Apple warning about malware and such.  
Your instructions would probably benefit from a "sudo xattr -d com.apple.quarantine /usr/local/bin/wasm-tools”

Now that it runs, I get this:

```scheme

[matthias @ CedarPark webracket (main)]$ racket webracket.rkt -r ../test.rkt

world

```

Okay not bad .. but I really want this to show in the browser … which I take it comes with `-b`.

All said and done, I think your docs need a write-up on how to run WebRacket programs in the browser.

But hey, this is huge progress. Thanks.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 25, 2026, 2:05pm UTC](https://racket.discourse.group/t/webracket/4123/16 "2026-02-25T14:05:38Z")

</div>

Great to hear `-r` now works. Getting something in the browser should now be easy.

> Okay not bad .. but I really want this to show in the browser … which I take it comes with `-b`.

This is where the two examples hello-world-2 and hello-world-3 enters the picture.

> **[webracket/examples/hello-world-2 at main · soegaard/webracket](https://github.com/soegaard/webracket/tree/main/examples/hello-world-2)**
>
> The WebRacket language is a subset of Racket that compiles to WebAssembly - soegaard/webracket

> **[webracket/examples/hello-world-3 at main · soegaard/webracket](https://github.com/soegaard/webracket/tree/main/examples/hello-world-3)**
>
> The WebRacket language is a subset of Racket that compiles to WebAssembly - soegaard/webracket

Let's look at the last one:

```scheme
;; Build a dom node with a small hello message.
(define content
  (sxml->dom
   '(div
      (h1 "Hello!")
      (p "This page was compiled from Racket to WebAssembly."))))

;; Get the (currently empty) body node and append our message.
(define body (js-document-body))
(js-append-child! body content)

;; Use the JavaScript Console for debugging.
(js-log "Hello!")

```

Inside the hello-world-3 folder:

```scheme
racket ../../webracket.rkt --stdlib --ffi dom -b hello-world-3.rkt

```

Then start a local web server:

```scheme
raco static-web

```

Go to the address printed by `static-web`.

> All said and done, I think your docs need a write-up on how to run WebRacket programs in the browser.

Agreed!

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 25, 2026, 2:14pm UTC](https://racket.discourse.group/t/webracket/4123/17 "2026-02-25T14:14:37Z")

</div>

@EmEf  
Thanks for the feedback - you must be the first besides me to give WebRacket a spin.

Based on the discussion, I have made some improvements:

The installation instructions for `wasm-tools` now include:

 ![image](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/4/4550e276fe649588e4ae189a6a70ada0384c1054.png)

I believe using "Privacy and Security" ought to be enough, but the command is a fine alternative.

Instructions for installing nanopass were added.

Instructions for installing webracket as a package was added.

The compiler driver was improved.

It now does preflight checks:

- checks that `wasm-tools` and `node` are in the path
- checks that `wasm-tools parse` is working
- checks that `node` understands the needed flags
- that all input and output files are actually files (not folders)
- that input and output files are distinct

Also, it now checks that output files actually are produced by the external tools as expected.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 25, 2026, 2:18pm UTC](https://racket.discourse.group/t/webracket/4123/18 "2026-02-25T14:18:57Z")

</div>

One more thing.

> Now that the compiler is somewhat stable, I need to flip it.  
> The standard library ought to be be included as default.  
> Then a switch `--no-stdlib` could omit it.

I decided to do the flip. The standard library in `stdlib/` is now automatically included.  
This means it is no longer needed to use `--stdlib` when compiling WebRacket programs.

Some test programs now need `--no-stdlib` but that's irrelevant to users.

Note: The downside of including the standard library is increased the compile times.  
The flag `--no-stdlib` can thus be used to opt put. Since the standard library contains `display` one can instead use the primitive `js-log` to write to the JavaScript console.

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [February 25, 2026, 11:09pm UTC](https://racket.discourse.group/t/webracket/4123/19 "2026-02-25T23:09:01Z")

</div>

On Feb 25, 2026, at 8:24 AM, Jens Axel Søgaard wrote “thanks for the feedback - you must be the first besides me to give WebRacket a spin.” ‘

Now we need six more people to do so to reach the magic level of dissemination 🙂

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [February 26, 2026, 12:14am UTC](https://racket.discourse.group/t/webracket/4123/20 "2026-02-26T00:14:42Z")

</div>

I tried to get the following small modification to run:

```scheme
(define (hello w)
  (define a (sxml->dom (hello/html w)))
  a)

(define (hello/html w)
  `(div (h2 "hello")
        (p (symbol->string w))))

;; I had initially included the following in `hello`
(define body (js-document-body))
(define more (hello 'Jens))
(js-append-child! body more)

```

I compiled it, and this succeeded w/o a problem. Then I ran `raco static-web` and opened localhost at the specified port.

-- I do get my "test.html" file _but_ when I open it in "localhost", I don't see anything. It's a blank page.

;; - - -

I pulled your repo and ran `race-setup` on it. I noticed two major problems:

1. It complles too many things, especially WebRacket files. Perhaps you should consider a different file extension (.wrkt?) and then exclude those in the "info.rkt" file when you make a package.

2. The name `js-eval` shows up as undefined. My guess is that this is needed somewhere in my example but I was reluctant to read a 120k file. Question: Am i missing one of your packages that this relies on?

FWIW I did get "examples-3" to run and display the desired output.

[Next page](https://racket.discourse.group/t/webracket/4123.md?page=2)
